OSDN Git Service

8ba304a6ec7f7d8c0e9369937516f52a8066745a
[android-x86/dalvik.git] / vm / native / dalvik_system_VMDebug.cpp
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.VMDebug
19  */
20 #include "Dalvik.h"
21 #include "alloc/HeapSource.h"
22 #include "native/InternalNativePriv.h"
23 #include "hprof/Hprof.h"
24
25 #include <string.h>
26 #include <unistd.h>
27
28
29 /*
30  * Extracts the fd from a FileDescriptor object.
31  *
32  * If an error is encountered, or the extracted descriptor is numerically
33  * invalid, this returns -1 with an exception raised.
34  */
35 static int getFileDescriptor(Object* obj)
36 {
37     assert(obj != NULL);
38     assert(strcmp(obj->clazz->descriptor, "Ljava/io/FileDescriptor;") == 0);
39
40     int fd = dvmGetFieldInt(obj, gDvm.offJavaIoFileDescriptor_descriptor);
41     if (fd < 0) {
42         dvmThrowRuntimeException("Invalid file descriptor");
43         return -1;
44     }
45
46     return fd;
47 }
48
49 /*
50  * static String[] getVmFeatureList()
51  *
52  * Return a set of strings describing available VM features (this is chiefly
53  * of interest to DDMS).
54  */
55 static void Dalvik_dalvik_system_VMDebug_getVmFeatureList(const u4* args, JValue* pResult) {
56     std::vector<std::string> features;
57     features.push_back("method-trace-profiling");
58     features.push_back("method-trace-profiling-streaming");
59     features.push_back("method-sample-profiling");
60     features.push_back("hprof-heap-dump");
61     features.push_back("hprof-heap-dump-streaming");
62
63     ArrayObject* result = dvmCreateStringArray(features);
64     dvmReleaseTrackedAlloc((Object*) result, dvmThreadSelf());
65     RETURN_PTR(result);
66 }
67
68 /* These must match the values in dalvik.system.VMDebug.
69  */
70 enum {
71     KIND_ALLOCATED_OBJECTS      = 1<<0,
72     KIND_ALLOCATED_BYTES        = 1<<1,
73     KIND_FREED_OBJECTS          = 1<<2,
74     KIND_FREED_BYTES            = 1<<3,
75     KIND_GC_INVOCATIONS         = 1<<4,
76     KIND_CLASS_INIT_COUNT       = 1<<5,
77     KIND_CLASS_INIT_TIME        = 1<<6,
78
79     /* These values exist for backward compatibility. */
80     KIND_EXT_ALLOCATED_OBJECTS = 1<<12,
81     KIND_EXT_ALLOCATED_BYTES   = 1<<13,
82     KIND_EXT_FREED_OBJECTS     = 1<<14,
83     KIND_EXT_FREED_BYTES       = 1<<15,
84
85     KIND_GLOBAL_ALLOCATED_OBJECTS   = KIND_ALLOCATED_OBJECTS,
86     KIND_GLOBAL_ALLOCATED_BYTES     = KIND_ALLOCATED_BYTES,
87     KIND_GLOBAL_FREED_OBJECTS       = KIND_FREED_OBJECTS,
88     KIND_GLOBAL_FREED_BYTES         = KIND_FREED_BYTES,
89     KIND_GLOBAL_GC_INVOCATIONS      = KIND_GC_INVOCATIONS,
90     KIND_GLOBAL_CLASS_INIT_COUNT    = KIND_CLASS_INIT_COUNT,
91     KIND_GLOBAL_CLASS_INIT_TIME     = KIND_CLASS_INIT_TIME,
92
93     KIND_THREAD_ALLOCATED_OBJECTS   = KIND_ALLOCATED_OBJECTS << 16,
94     KIND_THREAD_ALLOCATED_BYTES     = KIND_ALLOCATED_BYTES << 16,
95     KIND_THREAD_FREED_OBJECTS       = KIND_FREED_OBJECTS << 16,
96     KIND_THREAD_FREED_BYTES         = KIND_FREED_BYTES << 16,
97
98     KIND_THREAD_GC_INVOCATIONS      = KIND_GC_INVOCATIONS << 16,
99
100     // TODO: failedAllocCount, failedAllocSize
101 };
102
103 #define KIND_ALL_COUNTS 0xffffffff
104
105 /*
106  * Zero out the specified fields.
107  */
108 static void clearAllocProfStateFields(AllocProfState *allocProf,
109     unsigned int kinds)
110 {
111     if (kinds & KIND_ALLOCATED_OBJECTS) {
112         allocProf->allocCount = 0;
113     }
114     if (kinds & KIND_ALLOCATED_BYTES) {
115         allocProf->allocSize = 0;
116     }
117     if (kinds & KIND_FREED_OBJECTS) {
118         allocProf->freeCount = 0;
119     }
120     if (kinds & KIND_FREED_BYTES) {
121         allocProf->freeSize = 0;
122     }
123     if (kinds & KIND_GC_INVOCATIONS) {
124         allocProf->gcCount = 0;
125     }
126     if (kinds & KIND_CLASS_INIT_COUNT) {
127         allocProf->classInitCount = 0;
128     }
129     if (kinds & KIND_CLASS_INIT_TIME) {
130         allocProf->classInitTime = 0;
131     }
132 }
133
134 /*
135  * static void startAllocCounting()
136  *
137  * Reset the counters and enable counting.
138  *
139  * TODO: this currently only resets the per-thread counters for the current
140  * thread.  If we actually start using the per-thread counters we'll
141  * probably want to fix this.
142  */
143 static void Dalvik_dalvik_system_VMDebug_startAllocCounting(const u4* args,
144     JValue* pResult)
145 {
146     UNUSED_PARAMETER(args);
147
148     clearAllocProfStateFields(&gDvm.allocProf, KIND_ALL_COUNTS);
149     clearAllocProfStateFields(&dvmThreadSelf()->allocProf, KIND_ALL_COUNTS);
150     dvmStartAllocCounting();
151     RETURN_VOID();
152 }
153
154 /*
155  * public static void stopAllocCounting()
156  */
157 static void Dalvik_dalvik_system_VMDebug_stopAllocCounting(const u4* args,
158     JValue* pResult)
159 {
160     UNUSED_PARAMETER(args);
161
162     dvmStopAllocCounting();
163     RETURN_VOID();
164 }
165
166 /*
167  * private static int getAllocCount(int kind)
168  */
169 static void Dalvik_dalvik_system_VMDebug_getAllocCount(const u4* args,
170     JValue* pResult)
171 {
172     AllocProfState *allocProf;
173     unsigned int kind = args[0];
174     if (kind < (1<<16)) {
175         allocProf = &gDvm.allocProf;
176     } else {
177         allocProf = &dvmThreadSelf()->allocProf;
178         kind >>= 16;
179     }
180     switch (kind) {
181     case KIND_ALLOCATED_OBJECTS:
182         pResult->i = allocProf->allocCount;
183         break;
184     case KIND_ALLOCATED_BYTES:
185         pResult->i = allocProf->allocSize;
186         break;
187     case KIND_FREED_OBJECTS:
188         pResult->i = allocProf->freeCount;
189         break;
190     case KIND_FREED_BYTES:
191         pResult->i = allocProf->freeSize;
192         break;
193     case KIND_GC_INVOCATIONS:
194         pResult->i = allocProf->gcCount;
195         break;
196     case KIND_CLASS_INIT_COUNT:
197         pResult->i = allocProf->classInitCount;
198         break;
199     case KIND_CLASS_INIT_TIME:
200         /* convert nsec to usec, reduce to 32 bits */
201         pResult->i = (int) (allocProf->classInitTime / 1000);
202         break;
203     case KIND_EXT_ALLOCATED_OBJECTS:
204     case KIND_EXT_ALLOCATED_BYTES:
205     case KIND_EXT_FREED_OBJECTS:
206     case KIND_EXT_FREED_BYTES:
207         pResult->i = 0;  /* backward compatibility */
208         break;
209     default:
210         assert(false);
211         pResult->i = -1;
212     }
213 }
214
215 /*
216  * public static void resetAllocCount(int kinds)
217  */
218 static void Dalvik_dalvik_system_VMDebug_resetAllocCount(const u4* args,
219     JValue* pResult)
220 {
221     unsigned int kinds = args[0];
222     clearAllocProfStateFields(&gDvm.allocProf, kinds & 0xffff);
223     clearAllocProfStateFields(&dvmThreadSelf()->allocProf, kinds >> 16);
224     RETURN_VOID();
225 }
226
227 /*
228  * static void startMethodTracingDdmsImpl(int bufferSize, int flags,
229  *     boolean samplingEnabled, int intervalUs)
230  *
231  * Start method trace profiling, sending results directly to DDMS.
232  */
233 static void Dalvik_dalvik_system_VMDebug_startMethodTracingDdmsImpl(const u4* args,
234     JValue* pResult)
235 {
236     int bufferSize = args[0];
237     int flags = args[1];
238     bool samplingEnabled = args[2];
239     int intervalUs = args[3];
240     dvmMethodTraceStart("[DDMS]", -1, bufferSize, flags, true, samplingEnabled,
241         intervalUs);
242     RETURN_VOID();
243 }
244
245 /*
246  * static void startMethodTracingFd(String traceFileName, FileDescriptor fd,
247  *     int bufferSize, int flags)
248  *
249  * Start method trace profiling, sending results to a file descriptor.
250  */
251 static void Dalvik_dalvik_system_VMDebug_startMethodTracingFd(const u4* args,
252     JValue* pResult)
253 {
254     StringObject* traceFileStr = (StringObject*) args[0];
255     Object* traceFd = (Object*) args[1];
256     int bufferSize = args[2];
257     int flags = args[3];
258
259     int origFd = getFileDescriptor(traceFd);
260     if (origFd < 0)
261         RETURN_VOID();
262
263     int fd = dup(origFd);
264     if (fd < 0) {
265         dvmThrowExceptionFmt(gDvm.exRuntimeException,
266             "dup(%d) failed: %s", origFd, strerror(errno));
267         RETURN_VOID();
268     }
269
270     char* traceFileName = dvmCreateCstrFromString(traceFileStr);
271     if (traceFileName == NULL) {
272         RETURN_VOID();
273     }
274
275     dvmMethodTraceStart(traceFileName, fd, bufferSize, flags, false, false, 0);
276     free(traceFileName);
277     RETURN_VOID();
278 }
279
280 /*
281  * static void startMethodTracingFilename(String traceFileName, int bufferSize,
282  *     int flags)
283  *
284  * Start method trace profiling, sending results to a file.
285  */
286 static void Dalvik_dalvik_system_VMDebug_startMethodTracingFilename(const u4* args,
287     JValue* pResult)
288 {
289     StringObject* traceFileStr = (StringObject*) args[0];
290     int bufferSize = args[1];
291     int flags = args[2];
292
293     char* traceFileName = dvmCreateCstrFromString(traceFileStr);
294     if (traceFileName == NULL) {
295         RETURN_VOID();
296     }
297
298     dvmMethodTraceStart(traceFileName, -1, bufferSize, flags, false, false, 0);
299     free(traceFileName);
300     RETURN_VOID();
301 }
302
303 /*
304  * static boolean isMethodTracingActive()
305  *
306  * Determine whether method tracing is currently active.
307  */
308 static void Dalvik_dalvik_system_VMDebug_isMethodTracingActive(const u4* args,
309     JValue* pResult)
310 {
311     UNUSED_PARAMETER(args);
312
313     RETURN_BOOLEAN(dvmIsMethodTraceActive());
314 }
315
316 /*
317  * static void stopMethodTracing()
318  *
319  * Stop method tracing.
320  */
321 static void Dalvik_dalvik_system_VMDebug_stopMethodTracing(const u4* args,
322     JValue* pResult)
323 {
324     UNUSED_PARAMETER(args);
325
326     dvmMethodTraceStop();
327     RETURN_VOID();
328 }
329
330 /*
331  * static void startEmulatorTracing()
332  *
333  * Start sending method trace info to the emulator.
334  */
335 static void Dalvik_dalvik_system_VMDebug_startEmulatorTracing(const u4* args,
336     JValue* pResult)
337 {
338     UNUSED_PARAMETER(args);
339
340     dvmEmulatorTraceStart();
341     RETURN_VOID();
342 }
343
344 /*
345  * static void stopEmulatorTracing()
346  *
347  * Start sending method trace info to the emulator.
348  */
349 static void Dalvik_dalvik_system_VMDebug_stopEmulatorTracing(const u4* args,
350     JValue* pResult)
351 {
352     UNUSED_PARAMETER(args);
353
354     dvmEmulatorTraceStop();
355     RETURN_VOID();
356 }
357
358 /*
359  * static boolean isDebuggerConnected()
360  *
361  * Returns "true" if a debugger is attached.
362  */
363 static void Dalvik_dalvik_system_VMDebug_isDebuggerConnected(const u4* args,
364     JValue* pResult)
365 {
366     UNUSED_PARAMETER(args);
367
368     RETURN_BOOLEAN(dvmDbgIsDebuggerConnected());
369 }
370
371 /*
372  * static boolean isDebuggingEnabled()
373  *
374  * Returns "true" if debugging is enabled.
375  */
376 static void Dalvik_dalvik_system_VMDebug_isDebuggingEnabled(const u4* args,
377     JValue* pResult)
378 {
379     UNUSED_PARAMETER(args);
380
381     RETURN_BOOLEAN(gDvm.jdwpConfigured);
382 }
383
384 /*
385  * static long lastDebuggerActivity()
386  *
387  * Returns the time, in msec, since we last had an interaction with the
388  * debugger (send or receive).
389  */
390 static void Dalvik_dalvik_system_VMDebug_lastDebuggerActivity(const u4* args,
391     JValue* pResult)
392 {
393     UNUSED_PARAMETER(args);
394
395     RETURN_LONG(dvmDbgLastDebuggerActivity());
396 }
397
398 /*
399  * static void startInstructionCounting()
400  */
401 static void Dalvik_dalvik_system_VMDebug_startInstructionCounting(const u4* args,
402     JValue* pResult)
403 {
404     dvmStartInstructionCounting();
405     RETURN_VOID();
406 }
407
408 /*
409  * static void stopInstructionCounting()
410  */
411 static void Dalvik_dalvik_system_VMDebug_stopInstructionCounting(const u4* args,
412     JValue* pResult)
413 {
414     dvmStopInstructionCounting();
415     RETURN_VOID();
416 }
417
418 /*
419  * static boolean getInstructionCount(int[] counts)
420  *
421  * Grab a copy of the global instruction count array.
422  *
423  * Since the instruction counts aren't synchronized, we use sched_yield
424  * to improve our chances of finishing without contention.  (Only makes
425  * sense on a uniprocessor.)
426  */
427 static void Dalvik_dalvik_system_VMDebug_getInstructionCount(const u4* args,
428     JValue* pResult)
429 {
430     ArrayObject* countArray = (ArrayObject*) args[0];
431
432     if (countArray != NULL) {
433         int* storage = (int*)(void*)countArray->contents;
434         u4 length = countArray->length;
435
436         /*
437          * Ensure that we copy at most kNumPackedOpcodes
438          * elements, but no more than the length of the given array.
439          */
440         if (length > kNumPackedOpcodes) {
441             length = kNumPackedOpcodes;
442         }
443
444         sched_yield();
445         memcpy(storage, gDvm.executedInstrCounts, length * sizeof(int));
446     }
447
448     RETURN_VOID();
449 }
450
451 /*
452  * static boolean resetInstructionCount()
453  *
454  * Reset the instruction count array.
455  */
456 static void Dalvik_dalvik_system_VMDebug_resetInstructionCount(const u4* args,
457     JValue* pResult)
458 {
459     sched_yield();
460     memset(gDvm.executedInstrCounts, 0, kNumPackedOpcodes * sizeof(int));
461     RETURN_VOID();
462 }
463
464 /*
465  * static void printLoadedClasses(int flags)
466  *
467  * Dump the list of loaded classes.
468  */
469 static void Dalvik_dalvik_system_VMDebug_printLoadedClasses(const u4* args,
470     JValue* pResult)
471 {
472     int flags = args[0];
473
474     dvmDumpAllClasses(flags);
475
476     RETURN_VOID();
477 }
478
479 /*
480  * static int getLoadedClassCount()
481  *
482  * Return the number of loaded classes
483  */
484 static void Dalvik_dalvik_system_VMDebug_getLoadedClassCount(const u4* args,
485     JValue* pResult)
486 {
487     int count;
488
489     UNUSED_PARAMETER(args);
490
491     count = dvmGetNumLoadedClasses();
492
493     RETURN_INT(count);
494 }
495
496 /*
497  * Returns the thread-specific CPU-time clock value for the current thread,
498  * or -1 if the feature isn't supported.
499  */
500 static void Dalvik_dalvik_system_VMDebug_threadCpuTimeNanos(const u4* args,
501     JValue* pResult)
502 {
503     jlong result;
504
505 #ifdef HAVE_POSIX_CLOCKS
506     struct timespec now;
507     clock_gettime(CLOCK_THREAD_CPUTIME_ID, &now);
508     result = (jlong) (now.tv_sec*1000000000LL + now.tv_nsec);
509 #else
510     result = (jlong) -1;
511 #endif
512
513     RETURN_LONG(result);
514 }
515
516 /*
517  * static void dumpHprofData(String fileName, FileDescriptor fd)
518  *
519  * Cause "hprof" data to be dumped.  We can throw an IOException if an
520  * error occurs during file handling.
521  */
522 static void Dalvik_dalvik_system_VMDebug_dumpHprofData(const u4* args,
523     JValue* pResult)
524 {
525     StringObject* fileNameStr = (StringObject*) args[0];
526     Object* fileDescriptor = (Object*) args[1];
527     char* fileName;
528     int result;
529
530     /*
531      * Only one of these may be NULL.
532      */
533     if (fileNameStr == NULL && fileDescriptor == NULL) {
534         dvmThrowNullPointerException("fileName == null && fd == null");
535         RETURN_VOID();
536     }
537
538     if (fileNameStr != NULL) {
539         fileName = dvmCreateCstrFromString(fileNameStr);
540         if (fileName == NULL) {
541             /* unexpected -- malloc failure? */
542             dvmThrowRuntimeException("malloc failure?");
543             RETURN_VOID();
544         }
545     } else {
546         fileName = strdup("[fd]");
547     }
548
549     int fd = -1;
550     if (fileDescriptor != NULL) {
551         fd = getFileDescriptor(fileDescriptor);
552         if (fd < 0) {
553             free(fileName);
554             RETURN_VOID();
555         }
556     }
557
558     result = hprofDumpHeap(fileName, fd, false);
559     free(fileName);
560
561     if (result != 0) {
562         /* ideally we'd throw something more specific based on actual failure */
563         dvmThrowRuntimeException(
564             "Failure during heap dump; check log output for details");
565         RETURN_VOID();
566     }
567
568     RETURN_VOID();
569 }
570
571 /*
572  * static void dumpHprofDataDdms()
573  *
574  * Cause "hprof" data to be computed and sent directly to DDMS.
575  */
576 static void Dalvik_dalvik_system_VMDebug_dumpHprofDataDdms(const u4* args,
577     JValue* pResult)
578 {
579     int result;
580
581     result = hprofDumpHeap("[DDMS]", -1, true);
582
583     if (result != 0) {
584         /* ideally we'd throw something more specific based on actual failure */
585         dvmThrowRuntimeException(
586             "Failure during heap dump; check log output for details");
587         RETURN_VOID();
588     }
589
590     RETURN_VOID();
591 }
592
593 /*
594  * static boolean cacheRegisterMap(String classAndMethodDescr)
595  *
596  * If the specified class is loaded, and the named method exists, ensure
597  * that the method's register map is ready for use.  If the class/method
598  * cannot be found, nothing happens.
599  *
600  * This can improve the zygote's sharing of compressed register maps.  Do
601  * this after class preloading.
602  *
603  * Returns true if the register map is cached and ready, either as a result
604  * of this call or earlier activity.  Returns false if the class isn't loaded,
605  * if the method couldn't be found, or if the method has no register map.
606  *
607  * (Uncomment logs in dvmGetExpandedRegisterMap0() to gather stats.)
608  */
609 static void Dalvik_dalvik_system_VMDebug_cacheRegisterMap(const u4* args,
610     JValue* pResult)
611 {
612     StringObject* classAndMethodDescStr = (StringObject*) args[0];
613     ClassObject* clazz;
614     bool result = false;
615
616     if (classAndMethodDescStr == NULL) {
617         dvmThrowNullPointerException("classAndMethodDesc == null");
618         RETURN_VOID();
619     }
620
621     char* classAndMethodDesc = NULL;
622
623     /*
624      * Pick the string apart.  We have a local copy, so just modify it
625      * in place.
626      */
627     classAndMethodDesc = dvmCreateCstrFromString(classAndMethodDescStr);
628
629     char* methodName = strchr(classAndMethodDesc, '.');
630     if (methodName == NULL) {
631         dvmThrowRuntimeException("method name not found in string");
632         RETURN_VOID();
633     }
634     *methodName++ = '\0';
635
636     char* methodDescr = strchr(methodName, ':');
637     if (methodDescr == NULL) {
638         dvmThrowRuntimeException("method descriptor not found in string");
639         RETURN_VOID();
640     }
641     *methodDescr++ = '\0';
642
643     //ALOGD("GOT: %s %s %s", classAndMethodDesc, methodName, methodDescr);
644
645     /*
646      * Find the class, but only if it's already loaded.
647      */
648     clazz = dvmLookupClass(classAndMethodDesc, NULL, false);
649     if (clazz == NULL) {
650         ALOGD("Class %s not found in bootstrap loader", classAndMethodDesc);
651         goto bail;
652     }
653
654     Method* method;
655
656     /*
657      * Find the method, which could be virtual or direct, defined directly
658      * or inherited.
659      */
660     if (methodName[0] == '<') {
661         /*
662          * Constructor or class initializer.  Only need to examine the
663          * "direct" list, and don't need to search up the class hierarchy.
664          */
665         method = dvmFindDirectMethodByDescriptor(clazz, methodName,
666                     methodDescr);
667     } else {
668         /*
669          * Try both lists, and scan up the tree.
670          */
671         method = dvmFindVirtualMethodHierByDescriptor(clazz, methodName,
672                     methodDescr);
673         if (method == NULL) {
674             method = dvmFindDirectMethodHierByDescriptor(clazz, methodName,
675                         methodDescr);
676         }
677     }
678
679     if (method != NULL) {
680         /*
681          * Got it.  See if there's a register map here.
682          */
683         const RegisterMap* pMap;
684         pMap = dvmGetExpandedRegisterMap(method);
685         if (pMap == NULL) {
686             ALOGV("No map for %s.%s %s",
687                 classAndMethodDesc, methodName, methodDescr);
688         } else {
689             ALOGV("Found map %s.%s %s",
690                 classAndMethodDesc, methodName, methodDescr);
691             result = true;
692         }
693     } else {
694         ALOGV("Unable to find %s.%s %s",
695             classAndMethodDesc, methodName, methodDescr);
696     }
697
698 bail:
699     free(classAndMethodDesc);
700     RETURN_BOOLEAN(result);
701 }
702
703 /*
704  * static void dumpReferenceTables()
705  */
706 static void Dalvik_dalvik_system_VMDebug_dumpReferenceTables(const u4* args,
707     JValue* pResult)
708 {
709     UNUSED_PARAMETER(args);
710     UNUSED_PARAMETER(pResult);
711
712     ALOGI("--- reference table dump ---");
713     dvmDumpJniReferenceTables();
714     // could dump thread's internalLocalRefTable, probably not useful
715     // ditto for thread's jniMonitorRefTable
716     ALOGI("---");
717     RETURN_VOID();
718 }
719
720 /*
721  * static void crash()
722  *
723  * Dump the current thread's interpreted stack and abort the VM.  Useful
724  * for seeing both interpreted and native stack traces.
725  *
726  * (Might want to restrict this to debuggable processes as a security
727  * measure, or check SecurityManager.checkExit().)
728  */
729 static void Dalvik_dalvik_system_VMDebug_crash(const u4* args,
730     JValue* pResult)
731 {
732     UNUSED_PARAMETER(args);
733     UNUSED_PARAMETER(pResult);
734
735     ALOGW("Crashing VM on request");
736     dvmDumpThread(dvmThreadSelf(), false);
737     dvmAbort();
738 }
739
740 /*
741  * static void infopoint(int id)
742  *
743  * Provide a hook for gdb to hang to so that the VM can be stopped when
744  * user-tagged source locations are being executed.
745  */
746 static void Dalvik_dalvik_system_VMDebug_infopoint(const u4* args,
747     JValue* pResult)
748 {
749     gDvm.nativeDebuggerActive = true;
750
751     ALOGD("VMDebug infopoint %d hit", args[0]);
752
753     gDvm.nativeDebuggerActive = false;
754     RETURN_VOID();
755 }
756
757 static void Dalvik_dalvik_system_VMDebug_countInstancesOfClass(const u4* args,
758     JValue* pResult)
759 {
760     ClassObject* clazz = (ClassObject*)args[0];
761     bool countAssignable = args[1];
762     if (clazz == NULL) {
763         RETURN_LONG(0);
764     }
765     if (countAssignable) {
766         size_t count = dvmCountAssignableInstancesOfClass(clazz);
767         RETURN_LONG((long long)count);
768     } else {
769         size_t count = dvmCountInstancesOfClass(clazz);
770         RETURN_LONG((long long)count);
771     }
772 }
773
774 /*
775  * public static native void getHeapSpaceStats(long[] data)
776  */
777 static void Dalvik_dalvik_system_VMDebug_getHeapSpaceStats(const u4* args,
778     JValue* pResult)
779 {
780     ArrayObject* dataArray = (ArrayObject*) args[0];
781
782     if (dataArray == NULL || dataArray->length < 6) {
783       RETURN_VOID();
784     }
785
786     jlong* arr = (jlong*)(void*)dataArray->contents;
787
788     int j = 0;
789     size_t per_heap_allocated[2];
790     size_t per_heap_size[2];
791     memset(per_heap_allocated, 0, sizeof(per_heap_allocated));
792     memset(per_heap_size, 0, sizeof(per_heap_size));
793     dvmHeapSourceGetValue(HS_BYTES_ALLOCATED, (size_t*) &per_heap_allocated, 2);
794     dvmHeapSourceGetValue(HS_FOOTPRINT, (size_t*) &per_heap_size, 2);
795     jlong heapSize = per_heap_size[0];
796     jlong heapUsed = per_heap_allocated[0];
797     jlong heapFree = heapSize - heapUsed;
798     jlong zygoteSize = per_heap_size[1];
799     jlong zygoteUsed = per_heap_allocated[1];
800     jlong zygoteFree = zygoteSize - zygoteUsed;
801     arr[j++] = heapSize;
802     arr[j++] = heapUsed;
803     arr[j++] = heapFree;
804     arr[j++] = zygoteSize;
805     arr[j++] = zygoteUsed;
806     arr[j++] = zygoteFree;
807
808     RETURN_VOID();
809 }
810
811 const DalvikNativeMethod dvm_dalvik_system_VMDebug[] = {
812     { "getVmFeatureList",           "()[Ljava/lang/String;",
813         Dalvik_dalvik_system_VMDebug_getVmFeatureList },
814     { "getAllocCount",              "(I)I",
815         Dalvik_dalvik_system_VMDebug_getAllocCount },
816     { "getHeapSpaceStats",          "([J)V",
817         Dalvik_dalvik_system_VMDebug_getHeapSpaceStats },
818     { "resetAllocCount",            "(I)V",
819         Dalvik_dalvik_system_VMDebug_resetAllocCount },
820     { "startAllocCounting",         "()V",
821         Dalvik_dalvik_system_VMDebug_startAllocCounting },
822     { "stopAllocCounting",          "()V",
823         Dalvik_dalvik_system_VMDebug_stopAllocCounting },
824     { "startMethodTracingDdmsImpl", "(IIZI)V",
825         Dalvik_dalvik_system_VMDebug_startMethodTracingDdmsImpl },
826     { "startMethodTracingFd",       "(Ljava/lang/String;Ljava/io/FileDescriptor;II)V",
827         Dalvik_dalvik_system_VMDebug_startMethodTracingFd },
828     { "startMethodTracingFilename", "(Ljava/lang/String;II)V",
829         Dalvik_dalvik_system_VMDebug_startMethodTracingFilename },
830     { "isMethodTracingActive",      "()Z",
831         Dalvik_dalvik_system_VMDebug_isMethodTracingActive },
832     { "stopMethodTracing",          "()V",
833         Dalvik_dalvik_system_VMDebug_stopMethodTracing },
834     { "startEmulatorTracing",       "()V",
835         Dalvik_dalvik_system_VMDebug_startEmulatorTracing },
836     { "stopEmulatorTracing",        "()V",
837         Dalvik_dalvik_system_VMDebug_stopEmulatorTracing },
838     { "startInstructionCounting",   "()V",
839         Dalvik_dalvik_system_VMDebug_startInstructionCounting },
840     { "stopInstructionCounting",    "()V",
841         Dalvik_dalvik_system_VMDebug_stopInstructionCounting },
842     { "resetInstructionCount",      "()V",
843         Dalvik_dalvik_system_VMDebug_resetInstructionCount },
844     { "getInstructionCount",        "([I)V",
845         Dalvik_dalvik_system_VMDebug_getInstructionCount },
846     { "isDebuggerConnected",        "()Z",
847         Dalvik_dalvik_system_VMDebug_isDebuggerConnected },
848     { "isDebuggingEnabled",         "()Z",
849         Dalvik_dalvik_system_VMDebug_isDebuggingEnabled },
850     { "lastDebuggerActivity",       "()J",
851         Dalvik_dalvik_system_VMDebug_lastDebuggerActivity },
852     { "printLoadedClasses",         "(I)V",
853         Dalvik_dalvik_system_VMDebug_printLoadedClasses },
854     { "getLoadedClassCount",        "()I",
855         Dalvik_dalvik_system_VMDebug_getLoadedClassCount },
856     { "threadCpuTimeNanos",         "()J",
857         Dalvik_dalvik_system_VMDebug_threadCpuTimeNanos },
858     { "dumpHprofData",              "(Ljava/lang/String;Ljava/io/FileDescriptor;)V",
859         Dalvik_dalvik_system_VMDebug_dumpHprofData },
860     { "dumpHprofDataDdms",          "()V",
861         Dalvik_dalvik_system_VMDebug_dumpHprofDataDdms },
862     { "cacheRegisterMap",           "(Ljava/lang/String;)Z",
863         Dalvik_dalvik_system_VMDebug_cacheRegisterMap },
864     { "dumpReferenceTables",        "()V",
865         Dalvik_dalvik_system_VMDebug_dumpReferenceTables },
866     { "crash",                      "()V",
867         Dalvik_dalvik_system_VMDebug_crash },
868     { "infopoint",                 "(I)V",
869         Dalvik_dalvik_system_VMDebug_infopoint },
870     { "countInstancesOfClass",     "(Ljava/lang/Class;Z)J",
871         Dalvik_dalvik_system_VMDebug_countInstancesOfClass },
872     { NULL, NULL, NULL },
873 };