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 * dalvik.system.VMRuntime
19 */
20 #include "Dalvik.h"
21 #include "ScopedPthreadMutexLock.h"
22 #include "UniquePtr.h"
23 #include "alloc/HeapSource.h"
24 #include "alloc/Visit.h"
25 #include "libdex/DexClass.h"
26 #include "native/InternalNativePriv.h"
27
28 #include <limits.h>
29
30 #include <map>
31
32 /*
33 * public native float getTargetHeapUtilization()
34 *
35 * Gets the current ideal heap utilization, represented as a number
36 * between zero and one.
37 */
Dalvik_dalvik_system_VMRuntime_getTargetHeapUtilization(const u4 * args,JValue * pResult)38 static void Dalvik_dalvik_system_VMRuntime_getTargetHeapUtilization(
39 const u4* args, JValue* pResult)
40 {
41 UNUSED_PARAMETER(args);
42
43 RETURN_FLOAT(dvmGetTargetHeapUtilization());
44 }
45
46 /*
47 * native float nativeSetTargetHeapUtilization()
48 *
49 * Sets the current ideal heap utilization, represented as a number
50 * between zero and one. Returns the old utilization.
51 *
52 * Note that this is NOT static.
53 */
Dalvik_dalvik_system_VMRuntime_nativeSetTargetHeapUtilization(const u4 * args,JValue * pResult)54 static void Dalvik_dalvik_system_VMRuntime_nativeSetTargetHeapUtilization(
55 const u4* args, JValue* pResult)
56 {
57 dvmSetTargetHeapUtilization(dvmU4ToFloat(args[1]));
58
59 RETURN_VOID();
60 }
61
62 /*
63 * public native void startJitCompilation()
64 *
65 * Callback function from the framework to indicate that an app has gone
66 * through the startup phase and it is time to enable the JIT compiler.
67 */
Dalvik_dalvik_system_VMRuntime_startJitCompilation(const u4 * args,JValue * pResult)68 static void Dalvik_dalvik_system_VMRuntime_startJitCompilation(const u4* args,
69 JValue* pResult)
70 {
71 #if defined(WITH_JIT)
72 if (gDvm.executionMode == kExecutionModeJit && gDvmJit.disableJit == false) {
73 ScopedPthreadMutexLock lock(&gDvmJit.compilerLock);
74 gDvmJit.alreadyEnabledViaFramework = true;
75 pthread_cond_signal(&gDvmJit.compilerQueueActivity);
76 }
77 #endif
78 RETURN_VOID();
79 }
80
81 /*
82 * public native void disableJitCompilation()
83 *
84 * Callback function from the framework to indicate that a VM instance wants to
85 * permanently disable the JIT compiler. Currently only the system server uses
86 * this interface when it detects system-wide safe mode is enabled.
87 */
Dalvik_dalvik_system_VMRuntime_disableJitCompilation(const u4 * args,JValue * pResult)88 static void Dalvik_dalvik_system_VMRuntime_disableJitCompilation(const u4* args,
89 JValue* pResult)
90 {
91 #if defined(WITH_JIT)
92 if (gDvm.executionMode == kExecutionModeJit) {
93 gDvmJit.disableJit = true;
94 }
95 #endif
96 RETURN_VOID();
97 }
98
Dalvik_dalvik_system_VMRuntime_newNonMovableArray(const u4 * args,JValue * pResult)99 static void Dalvik_dalvik_system_VMRuntime_newNonMovableArray(const u4* args,
100 JValue* pResult)
101 {
102 ClassObject* elementClass = (ClassObject*) args[1];
103 int length = args[2];
104
105 if (elementClass == NULL) {
106 dvmThrowNullPointerException("elementClass == null");
107 RETURN_VOID();
108 }
109 if (length < 0) {
110 dvmThrowNegativeArraySizeException(length);
111 RETURN_VOID();
112 }
113
114 // TODO: right now, we don't have a copying collector, so there's no need
115 // to do anything special here, but we ought to pass the non-movability
116 // through to the allocator.
117 ClassObject* arrayClass = dvmFindArrayClassForElement(elementClass);
118 ArrayObject* newArray = dvmAllocArrayByClass(arrayClass,
119 length,
120 ALLOC_NON_MOVING);
121 if (newArray == NULL) {
122 assert(dvmCheckException(dvmThreadSelf()));
123 RETURN_VOID();
124 }
125 dvmReleaseTrackedAlloc((Object*) newArray, NULL);
126
127 RETURN_PTR(newArray);
128 }
129
Dalvik_dalvik_system_VMRuntime_addressOf(const u4 * args,JValue * pResult)130 static void Dalvik_dalvik_system_VMRuntime_addressOf(const u4* args,
131 JValue* pResult)
132 {
133 ArrayObject* array = (ArrayObject*) args[1];
134 if (!dvmIsArray(array)) {
135 dvmThrowIllegalArgumentException(NULL);
136 RETURN_VOID();
137 }
138 // TODO: we should also check that this is a non-movable array.
139 s8 result = (uintptr_t) array->contents;
140 RETURN_LONG(result);
141 }
142
Dalvik_dalvik_system_VMRuntime_clearGrowthLimit(const u4 * args,JValue * pResult)143 static void Dalvik_dalvik_system_VMRuntime_clearGrowthLimit(const u4* args,
144 JValue* pResult)
145 {
146 dvmClearGrowthLimit();
147 RETURN_VOID();
148 }
149
Dalvik_dalvik_system_VMRuntime_isDebuggerActive(const u4 * args,JValue * pResult)150 static void Dalvik_dalvik_system_VMRuntime_isDebuggerActive(
151 const u4* args, JValue* pResult)
152 {
153 RETURN_BOOLEAN(gDvm.debuggerActive || gDvm.nativeDebuggerActive);
154 }
155
Dalvik_dalvik_system_VMRuntime_properties(const u4 * args,JValue * pResult)156 static void Dalvik_dalvik_system_VMRuntime_properties(const u4* args,
157 JValue* pResult)
158 {
159 ArrayObject* result = dvmCreateStringArray(*gDvm.properties);
160 dvmReleaseTrackedAlloc((Object*) result, dvmThreadSelf());
161 RETURN_PTR(result);
162 }
163
returnCString(JValue * pResult,const char * s)164 static void returnCString(JValue* pResult, const char* s)
165 {
166 Object* result = (Object*) dvmCreateStringFromCstr(s);
167 dvmReleaseTrackedAlloc(result, dvmThreadSelf());
168 RETURN_PTR(result);
169 }
170
Dalvik_dalvik_system_VMRuntime_bootClassPath(const u4 * args,JValue * pResult)171 static void Dalvik_dalvik_system_VMRuntime_bootClassPath(const u4* args,
172 JValue* pResult)
173 {
174 returnCString(pResult, gDvm.bootClassPathStr);
175 }
176
Dalvik_dalvik_system_VMRuntime_classPath(const u4 * args,JValue * pResult)177 static void Dalvik_dalvik_system_VMRuntime_classPath(const u4* args,
178 JValue* pResult)
179 {
180 returnCString(pResult, gDvm.classPathStr);
181 }
182
Dalvik_dalvik_system_VMRuntime_vmVersion(const u4 * args,JValue * pResult)183 static void Dalvik_dalvik_system_VMRuntime_vmVersion(const u4* args,
184 JValue* pResult)
185 {
186 char buf[64];
187 sprintf(buf, "%d.%d.%d",
188 DALVIK_MAJOR_VERSION, DALVIK_MINOR_VERSION, DALVIK_BUG_VERSION);
189 returnCString(pResult, buf);
190 }
191
Dalvik_dalvik_system_VMRuntime_vmLibrary(const u4 * args,JValue * pResult)192 static void Dalvik_dalvik_system_VMRuntime_vmLibrary(const u4* args,
193 JValue* pResult)
194 {
195 returnCString(pResult, "libdvm.so");
196 }
197
Dalvik_dalvik_system_VMRuntime_setTargetSdkVersion(const u4 * args,JValue * pResult)198 static void Dalvik_dalvik_system_VMRuntime_setTargetSdkVersion(const u4* args,
199 JValue* pResult)
200 {
201 // This is the target SDK version of the app we're about to run.
202 // Note that this value may be CUR_DEVELOPMENT (10000).
203 // Note that this value may be 0, meaning "current".
204 int targetSdkVersion = args[1];
205 if (targetSdkVersion > 0 && targetSdkVersion <= 13 /* honeycomb-mr2 */) {
206 if (gDvmJni.useCheckJni) {
207 ALOGI("CheckJNI enabled: not enabling JNI app bug workarounds.");
208 } else {
209 ALOGI("Enabling JNI app bug workarounds for target SDK version %i...",
210 targetSdkVersion);
211 gDvmJni.workAroundAppJniBugs = true;
212 }
213 }
214 RETURN_VOID();
215 }
216
Dalvik_dalvik_system_VMRuntime_registerNativeAllocation(const u4 * args,JValue * pResult)217 static void Dalvik_dalvik_system_VMRuntime_registerNativeAllocation(const u4* args,
218 JValue* pResult)
219 {
220 int bytes = args[1];
221 if (bytes < 0) {
222 dvmThrowRuntimeException("allocation size negative");
223 } else {
224 dvmHeapSourceRegisterNativeAllocation(bytes);
225 }
226 RETURN_VOID();
227 }
228
Dalvik_dalvik_system_VMRuntime_registerNativeFree(const u4 * args,JValue * pResult)229 static void Dalvik_dalvik_system_VMRuntime_registerNativeFree(const u4* args,
230 JValue* pResult)
231 {
232 int bytes = args[1];
233 if (bytes < 0) {
234 dvmThrowRuntimeException("allocation size negative");
235 } else {
236 dvmHeapSourceRegisterNativeFree(bytes);
237 }
238 RETURN_VOID();
239 }
240
getDvmDexFromClassPathEntry(ClassPathEntry * cpe)241 static DvmDex* getDvmDexFromClassPathEntry(ClassPathEntry* cpe) {
242 if (cpe->kind == kCpeDex) {
243 return ((RawDexFile*) cpe->ptr)->pDvmDex;
244 }
245 if (cpe->kind == kCpeJar) {
246 return ((JarFile*) cpe->ptr)->pDvmDex;
247 }
248 LOG_ALWAYS_FATAL("Unknown cpe->kind=%d", cpe->kind);
249 }
250
251 typedef std::map<std::string, StringObject*> StringTable;
252
preloadDexCachesStringsVisitor(void * addr,u4 threadId,RootType type,void * arg)253 static void preloadDexCachesStringsVisitor(void* addr, u4 threadId, RootType type, void* arg) {
254 StringTable& table = *(StringTable*) arg;
255 StringObject* strObj = *(StringObject**) addr;
256 LOG_FATAL_IF(strObj->clazz != gDvm.classJavaLangString, "Unknown class for supposed string");
257 char* newStr = dvmCreateCstrFromString(strObj);
258 // ALOGI("VMRuntime.preloadDexCaches interned=%s", newStr);
259 table[newStr] = strObj;
260 free(newStr);
261 }
262
263 // Based on dvmResolveString.
preloadDexCachesResolveString(DvmDex * pDvmDex,uint32_t stringIdx,StringTable & strings)264 static void preloadDexCachesResolveString(DvmDex* pDvmDex,
265 uint32_t stringIdx,
266 StringTable& strings) {
267 StringObject* string = dvmDexGetResolvedString(pDvmDex, stringIdx);
268 if (string != NULL) {
269 return;
270 }
271 const DexFile* pDexFile = pDvmDex->pDexFile;
272 uint32_t utf16Size;
273 const char* utf8 = dexStringAndSizeById(pDexFile, stringIdx, &utf16Size);
274 string = strings[utf8];
275 if (string == NULL) {
276 return;
277 }
278 // ALOGI("VMRuntime.preloadDexCaches found string=%s", utf8);
279 dvmDexSetResolvedString(pDvmDex, stringIdx, string);
280 }
281
282 // Based on dvmResolveClass.
preloadDexCachesResolveType(DvmDex * pDvmDex,uint32_t typeIdx)283 static void preloadDexCachesResolveType(DvmDex* pDvmDex, uint32_t typeIdx) {
284 ClassObject* clazz = dvmDexGetResolvedClass(pDvmDex, typeIdx);
285 if (clazz != NULL) {
286 return;
287 }
288 const DexFile* pDexFile = pDvmDex->pDexFile;
289 const char* className = dexStringByTypeIdx(pDexFile, typeIdx);
290 if (className[0] != '\0' && className[1] == '\0') {
291 /* primitive type */
292 clazz = dvmFindPrimitiveClass(className[0]);
293 } else {
294 clazz = dvmLookupClass(className, NULL, true);
295 }
296 if (clazz == NULL) {
297 return;
298 }
299 // Skip uninitialized classes because filled cache entry implies it is initialized.
300 if (!dvmIsClassInitialized(clazz)) {
301 // ALOGI("VMRuntime.preloadDexCaches uninitialized clazz=%s", className);
302 return;
303 }
304 // ALOGI("VMRuntime.preloadDexCaches found clazz=%s", className);
305 dvmDexSetResolvedClass(pDvmDex, typeIdx, clazz);
306 }
307
308 // Based on dvmResolveInstField/dvmResolveStaticField.
preloadDexCachesResolveField(DvmDex * pDvmDex,uint32_t fieldIdx,bool instance)309 static void preloadDexCachesResolveField(DvmDex* pDvmDex, uint32_t fieldIdx, bool instance) {
310 Field* field = dvmDexGetResolvedField(pDvmDex, fieldIdx);
311 if (field != NULL) {
312 return;
313 }
314 const DexFile* pDexFile = pDvmDex->pDexFile;
315 const DexFieldId* pFieldId = dexGetFieldId(pDexFile, fieldIdx);
316 ClassObject* clazz = dvmDexGetResolvedClass(pDvmDex, pFieldId->classIdx);
317 if (clazz == NULL) {
318 return;
319 }
320 // Skip static fields for uninitialized classes because a filled
321 // cache entry implies the class is initialized.
322 if (!instance && !dvmIsClassInitialized(clazz)) {
323 return;
324 }
325 const char* fieldName = dexStringById(pDexFile, pFieldId->nameIdx);
326 const char* signature = dexStringByTypeIdx(pDexFile, pFieldId->typeIdx);
327 if (instance) {
328 field = dvmFindInstanceFieldHier(clazz, fieldName, signature);
329 } else {
330 field = dvmFindStaticFieldHier(clazz, fieldName, signature);
331 }
332 if (field == NULL) {
333 return;
334 }
335 // ALOGI("VMRuntime.preloadDexCaches found field %s %s.%s",
336 // signature, clazz->descriptor, fieldName);
337 dvmDexSetResolvedField(pDvmDex, fieldIdx, field);
338 }
339
340 // Based on dvmResolveMethod.
preloadDexCachesResolveMethod(DvmDex * pDvmDex,uint32_t methodIdx,MethodType methodType)341 static void preloadDexCachesResolveMethod(DvmDex* pDvmDex,
342 uint32_t methodIdx,
343 MethodType methodType) {
344 Method* method = dvmDexGetResolvedMethod(pDvmDex, methodIdx);
345 if (method != NULL) {
346 return;
347 }
348 const DexFile* pDexFile = pDvmDex->pDexFile;
349 const DexMethodId* pMethodId = dexGetMethodId(pDexFile, methodIdx);
350 ClassObject* clazz = dvmDexGetResolvedClass(pDvmDex, pMethodId->classIdx);
351 if (clazz == NULL) {
352 return;
353 }
354 // Skip static methods for uninitialized classes because a filled
355 // cache entry implies the class is initialized.
356 if ((methodType == METHOD_STATIC) && !dvmIsClassInitialized(clazz)) {
357 return;
358 }
359 const char* methodName = dexStringById(pDexFile, pMethodId->nameIdx);
360 DexProto proto;
361 dexProtoSetFromMethodId(&proto, pDexFile, pMethodId);
362
363 if (methodType == METHOD_DIRECT) {
364 method = dvmFindDirectMethod(clazz, methodName, &proto);
365 } else if (methodType == METHOD_STATIC) {
366 method = dvmFindDirectMethodHier(clazz, methodName, &proto);
367 } else {
368 method = dvmFindVirtualMethodHier(clazz, methodName, &proto);
369 }
370 if (method == NULL) {
371 return;
372 }
373 // ALOGI("VMRuntime.preloadDexCaches found method %s.%s",
374 // clazz->descriptor, methodName);
375 dvmDexSetResolvedMethod(pDvmDex, methodIdx, method);
376 }
377
378 struct DexCacheStats {
379 uint32_t numStrings;
380 uint32_t numTypes;
381 uint32_t numFields;
382 uint32_t numMethods;
DexCacheStatsDexCacheStats383 DexCacheStats() : numStrings(0), numTypes(0), numFields(0), numMethods(0) {};
384 };
385
386 static const bool kPreloadDexCachesEnabled = true;
387
388 // Disabled because it takes a long time (extra half second) but
389 // gives almost no benefit in terms of saving private dirty pages.
390 static const bool kPreloadDexCachesStrings = false;
391
392 static const bool kPreloadDexCachesTypes = true;
393 static const bool kPreloadDexCachesFieldsAndMethods = true;
394
395 static const bool kPreloadDexCachesCollectStats = false;
396
preloadDexCachesStatsTotal(DexCacheStats * total)397 static void preloadDexCachesStatsTotal(DexCacheStats* total) {
398 if (!kPreloadDexCachesCollectStats) {
399 return;
400 }
401
402 for (ClassPathEntry* cpe = gDvm.bootClassPath; cpe->kind != kCpeLastEntry; cpe++) {
403 DvmDex* pDvmDex = getDvmDexFromClassPathEntry(cpe);
404 const DexHeader* pHeader = pDvmDex->pHeader;
405 total->numStrings += pHeader->stringIdsSize;
406 total->numFields += pHeader->fieldIdsSize;
407 total->numMethods += pHeader->methodIdsSize;
408 total->numTypes += pHeader->typeIdsSize;
409 }
410 }
411
preloadDexCachesStatsFilled(DexCacheStats * filled)412 static void preloadDexCachesStatsFilled(DexCacheStats* filled) {
413 if (!kPreloadDexCachesCollectStats) {
414 return;
415 }
416 for (ClassPathEntry* cpe = gDvm.bootClassPath; cpe->kind != kCpeLastEntry; cpe++) {
417 DvmDex* pDvmDex = getDvmDexFromClassPathEntry(cpe);
418 const DexHeader* pHeader = pDvmDex->pHeader;
419 for (size_t i = 0; i < pHeader->stringIdsSize; i++) {
420 StringObject* string = dvmDexGetResolvedString(pDvmDex, i);
421 if (string != NULL) {
422 filled->numStrings++;
423 }
424 }
425 for (size_t i = 0; i < pHeader->typeIdsSize; i++) {
426 ClassObject* clazz = dvmDexGetResolvedClass(pDvmDex, i);
427 if (clazz != NULL) {
428 filled->numTypes++;
429 }
430 }
431 for (size_t i = 0; i < pHeader->fieldIdsSize; i++) {
432 Field* field = dvmDexGetResolvedField(pDvmDex, i);
433 if (field != NULL) {
434 filled->numFields++;
435 }
436 }
437 for (size_t i = 0; i < pHeader->methodIdsSize; i++) {
438 Method* method = dvmDexGetResolvedMethod(pDvmDex, i);
439 if (method != NULL) {
440 filled->numMethods++;
441 }
442 }
443 }
444 }
445
Dalvik_dalvik_system_VMRuntime_preloadDexCaches(const u4 * args,JValue * pResult)446 static void Dalvik_dalvik_system_VMRuntime_preloadDexCaches(const u4* args, JValue* pResult)
447 {
448 if (!kPreloadDexCachesEnabled) {
449 return;
450 }
451
452 DexCacheStats total;
453 DexCacheStats before;
454 if (kPreloadDexCachesCollectStats) {
455 ALOGI("VMRuntime.preloadDexCaches starting");
456 preloadDexCachesStatsTotal(&total);
457 preloadDexCachesStatsFilled(&before);
458 }
459
460 // We use a std::map to avoid heap allocating StringObjects to lookup in gDvm.literalStrings
461 StringTable strings;
462 if (kPreloadDexCachesStrings) {
463 dvmLockMutex(&gDvm.internLock);
464 dvmHashTableLock(gDvm.literalStrings);
465 for (int i = 0; i < gDvm.literalStrings->tableSize; ++i) {
466 HashEntry *entry = &gDvm.literalStrings->pEntries[i];
467 if (entry->data != NULL && entry->data != HASH_TOMBSTONE) {
468 preloadDexCachesStringsVisitor(&entry->data, 0, ROOT_INTERNED_STRING, &strings);
469 }
470 }
471 dvmHashTableUnlock(gDvm.literalStrings);
472 dvmUnlockMutex(&gDvm.internLock);
473 }
474
475 for (ClassPathEntry* cpe = gDvm.bootClassPath; cpe->kind != kCpeLastEntry; cpe++) {
476 DvmDex* pDvmDex = getDvmDexFromClassPathEntry(cpe);
477 const DexHeader* pHeader = pDvmDex->pHeader;
478 const DexFile* pDexFile = pDvmDex->pDexFile;
479
480 if (kPreloadDexCachesStrings) {
481 for (size_t i = 0; i < pHeader->stringIdsSize; i++) {
482 preloadDexCachesResolveString(pDvmDex, i, strings);
483 }
484 }
485
486 if (kPreloadDexCachesTypes) {
487 for (size_t i = 0; i < pHeader->typeIdsSize; i++) {
488 preloadDexCachesResolveType(pDvmDex, i);
489 }
490 }
491
492 if (kPreloadDexCachesFieldsAndMethods) {
493 for (size_t classDefIndex = 0;
494 classDefIndex < pHeader->classDefsSize;
495 classDefIndex++) {
496 const DexClassDef* pClassDef = dexGetClassDef(pDexFile, classDefIndex);
497 const u1* pEncodedData = dexGetClassData(pDexFile, pClassDef);
498 UniquePtr<DexClassData> pClassData(dexReadAndVerifyClassData(&pEncodedData, NULL));
499 if (pClassData.get() == NULL) {
500 continue;
501 }
502 for (uint32_t fieldIndex = 0;
503 fieldIndex < pClassData->header.staticFieldsSize;
504 fieldIndex++) {
505 const DexField* pField = &pClassData->staticFields[fieldIndex];
506 preloadDexCachesResolveField(pDvmDex, pField->fieldIdx, false);
507 }
508 for (uint32_t fieldIndex = 0;
509 fieldIndex < pClassData->header.instanceFieldsSize;
510 fieldIndex++) {
511 const DexField* pField = &pClassData->instanceFields[fieldIndex];
512 preloadDexCachesResolveField(pDvmDex, pField->fieldIdx, true);
513 }
514 for (uint32_t methodIndex = 0;
515 methodIndex < pClassData->header.directMethodsSize;
516 methodIndex++) {
517 const DexMethod* pDexMethod = &pClassData->directMethods[methodIndex];
518 MethodType methodType = (((pDexMethod->accessFlags & ACC_STATIC) != 0) ?
519 METHOD_STATIC :
520 METHOD_DIRECT);
521 preloadDexCachesResolveMethod(pDvmDex, pDexMethod->methodIdx, methodType);
522 }
523 for (uint32_t methodIndex = 0;
524 methodIndex < pClassData->header.virtualMethodsSize;
525 methodIndex++) {
526 const DexMethod* pDexMethod = &pClassData->virtualMethods[methodIndex];
527 preloadDexCachesResolveMethod(pDvmDex, pDexMethod->methodIdx, METHOD_VIRTUAL);
528 }
529 }
530 }
531 }
532
533 if (kPreloadDexCachesCollectStats) {
534 DexCacheStats after;
535 preloadDexCachesStatsFilled(&after);
536 ALOGI("VMRuntime.preloadDexCaches strings total=%d before=%d after=%d",
537 total.numStrings, before.numStrings, after.numStrings);
538 ALOGI("VMRuntime.preloadDexCaches types total=%d before=%d after=%d",
539 total.numTypes, before.numTypes, after.numTypes);
540 ALOGI("VMRuntime.preloadDexCaches fields total=%d before=%d after=%d",
541 total.numFields, before.numFields, after.numFields);
542 ALOGI("VMRuntime.preloadDexCaches methods total=%d before=%d after=%d",
543 total.numMethods, before.numMethods, after.numMethods);
544 ALOGI("VMRuntime.preloadDexCaches finished");
545 }
546
547 RETURN_VOID();
548 }
549
550 const DalvikNativeMethod dvm_dalvik_system_VMRuntime[] = {
551 { "addressOf", "(Ljava/lang/Object;)J",
552 Dalvik_dalvik_system_VMRuntime_addressOf },
553 { "bootClassPath", "()Ljava/lang/String;",
554 Dalvik_dalvik_system_VMRuntime_bootClassPath },
555 { "classPath", "()Ljava/lang/String;",
556 Dalvik_dalvik_system_VMRuntime_classPath },
557 { "clearGrowthLimit", "()V",
558 Dalvik_dalvik_system_VMRuntime_clearGrowthLimit },
559 { "disableJitCompilation", "()V",
560 Dalvik_dalvik_system_VMRuntime_disableJitCompilation },
561 { "isDebuggerActive", "()Z",
562 Dalvik_dalvik_system_VMRuntime_isDebuggerActive },
563 { "getTargetHeapUtilization", "()F",
564 Dalvik_dalvik_system_VMRuntime_getTargetHeapUtilization },
565 { "nativeSetTargetHeapUtilization", "(F)V",
566 Dalvik_dalvik_system_VMRuntime_nativeSetTargetHeapUtilization },
567 { "newNonMovableArray", "(Ljava/lang/Class;I)Ljava/lang/Object;",
568 Dalvik_dalvik_system_VMRuntime_newNonMovableArray },
569 { "properties", "()[Ljava/lang/String;",
570 Dalvik_dalvik_system_VMRuntime_properties },
571 { "setTargetSdkVersion", "(I)V",
572 Dalvik_dalvik_system_VMRuntime_setTargetSdkVersion },
573 { "startJitCompilation", "()V",
574 Dalvik_dalvik_system_VMRuntime_startJitCompilation },
575 { "vmVersion", "()Ljava/lang/String;",
576 Dalvik_dalvik_system_VMRuntime_vmVersion },
577 { "vmLibrary", "()Ljava/lang/String;",
578 Dalvik_dalvik_system_VMRuntime_vmLibrary },
579 { "registerNativeAllocation", "(I)V",
580 Dalvik_dalvik_system_VMRuntime_registerNativeAllocation },
581 { "registerNativeFree", "(I)V",
582 Dalvik_dalvik_system_VMRuntime_registerNativeFree },
583 { "preloadDexCaches", "()V",
584 Dalvik_dalvik_system_VMRuntime_preloadDexCaches },
585 { NULL, NULL, NULL },
586 };
587