OSDN Git Service

am de9e2b90: Bug fixes for ld/st elimination.
[android-x86/dalvik.git] / vm / Misc.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  * Miscellaneous utility functions.
19  */
20 #include "Dalvik.h"
21
22 #include <stdlib.h>
23 #include <stddef.h>
24 #include <string.h>
25 #include <strings.h>
26 #include <ctype.h>
27 #include <time.h>
28 #include <sys/time.h>
29 #include <fcntl.h>
30 #include <cutils/ashmem.h>
31 #include <sys/mman.h>
32
33 /*
34  * Print a hex dump in this format:
35  *
36 01234567: 00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff  0123456789abcdef\n
37  *
38  * If "mode" is kHexDumpLocal, we start at offset zero, and show a full
39  * 16 bytes on the first line.  If it's kHexDumpMem, we make this look
40  * like a memory dump, using the actual address, outputting a partial line
41  * if "vaddr" isn't aligned on a 16-byte boundary.
42  *
43  * "priority" and "tag" determine the values passed to the log calls.
44  *
45  * Does not use printf() or other string-formatting calls.
46  */
47 void dvmPrintHexDumpEx(int priority, const char* tag, const void* vaddr,
48     size_t length, HexDumpMode mode)
49 {
50     static const char gHexDigit[] = "0123456789abcdef";
51     const unsigned char* addr = (const unsigned char*)vaddr;
52     char out[77];           /* exact fit */
53     unsigned int offset;    /* offset to show while printing */
54     char* hex;
55     char* asc;
56     int gap;
57     //int trickle = 0;
58
59     if (mode == kHexDumpLocal)
60         offset = 0;
61     else
62         offset = (int) addr;
63
64     memset(out, ' ', sizeof(out)-1);
65     out[8] = ':';
66     out[sizeof(out)-2] = '\n';
67     out[sizeof(out)-1] = '\0';
68
69     gap = (int) offset & 0x0f;
70     while (length) {
71         unsigned int lineOffset = offset & ~0x0f;
72         int i, count;
73
74         hex = out;
75         asc = out + 59;
76
77         for (i = 0; i < 8; i++) {
78             *hex++ = gHexDigit[lineOffset >> 28];
79             lineOffset <<= 4;
80         }
81         hex++;
82         hex++;
83
84         count = ((int)length > 16-gap) ? 16-gap : (int)length; /* cap length */
85         assert(count != 0);
86         assert(count+gap <= 16);
87
88         if (gap) {
89             /* only on first line */
90             hex += gap * 3;
91             asc += gap;
92         }
93
94         for (i = gap ; i < count+gap; i++) {
95             *hex++ = gHexDigit[*addr >> 4];
96             *hex++ = gHexDigit[*addr & 0x0f];
97             hex++;
98             if (*addr >= 0x20 && *addr < 0x7f /*isprint(*addr)*/)
99                 *asc++ = *addr;
100             else
101                 *asc++ = '.';
102             addr++;
103         }
104         for ( ; i < 16; i++) {
105             /* erase extra stuff; only happens on last line */
106             *hex++ = ' ';
107             *hex++ = ' ';
108             hex++;
109             *asc++ = ' ';
110         }
111
112         LOG_PRI(priority, tag, "%s", out);
113 #if 0 //def HAVE_ANDROID_OS
114         /*
115          * We can overrun logcat easily by writing at full speed.  On the
116          * other hand, we can make Eclipse time out if we're showing
117          * packet dumps while debugging JDWP.
118          */
119         {
120             if (trickle++ == 8) {
121                 trickle = 0;
122                 usleep(20000);
123             }
124         }
125 #endif
126
127         gap = 0;
128         length -= count;
129         offset += count;
130     }
131 }
132
133
134 /*
135  * Fill out a DebugOutputTarget, suitable for printing to the log.
136  */
137 void dvmCreateLogOutputTarget(DebugOutputTarget* target, int priority,
138     const char* tag)
139 {
140     assert(target != NULL);
141     assert(tag != NULL);
142
143     target->which = kDebugTargetLog;
144     target->data.log.priority = priority;
145     target->data.log.tag = tag;
146 }
147
148 /*
149  * Fill out a DebugOutputTarget suitable for printing to a file pointer.
150  */
151 void dvmCreateFileOutputTarget(DebugOutputTarget* target, FILE* fp)
152 {
153     assert(target != NULL);
154     assert(fp != NULL);
155
156     target->which = kDebugTargetFile;
157     target->data.file.fp = fp;
158 }
159
160 /*
161  * Free "target" and any associated data.
162  */
163 void dvmFreeOutputTarget(DebugOutputTarget* target)
164 {
165     free(target);
166 }
167
168 /*
169  * Print a debug message, to either a file or the log.
170  */
171 void dvmPrintDebugMessage(const DebugOutputTarget* target, const char* format,
172     ...)
173 {
174     va_list args;
175
176     va_start(args, format);
177
178     switch (target->which) {
179     case kDebugTargetLog:
180         LOG_PRI_VA(target->data.log.priority, target->data.log.tag,
181             format, args);
182         break;
183     case kDebugTargetFile:
184         vfprintf(target->data.file.fp, format, args);
185         break;
186     default:
187         LOGE("unexpected 'which' %d\n", target->which);
188         break;
189     }
190
191     va_end(args);
192 }
193
194
195 /*
196  * Return a newly-allocated string in which all occurrences of '.' have
197  * been changed to '/'.  If we find a '/' in the original string, NULL
198  * is returned to avoid ambiguity.
199  */
200 char* dvmDotToSlash(const char* str)
201 {
202     char* newStr = strdup(str);
203     char* cp = newStr;
204
205     if (newStr == NULL)
206         return NULL;
207
208     while (*cp != '\0') {
209         if (*cp == '/') {
210             assert(false);
211             return NULL;
212         }
213         if (*cp == '.')
214             *cp = '/';
215         cp++;
216     }
217
218     return newStr;
219 }
220
221 char* dvmHumanReadableDescriptor(const char* descriptor)
222 {
223     // Count the number of '['s to get the dimensionality.
224     const char* c = descriptor;
225     size_t dim = 0;
226     while (*c == '[') {
227         dim++;
228         c++;
229     }
230
231     // Work out how large the result will be.
232     size_t resultLength;
233     if (*c == 'L') {
234         // "[[La/b/C;" -> "a.b.C[][]".
235         resultLength = strlen(c) - 2 + 2*dim;
236         c++; // Skip the 'L'.
237     } else {
238         // "[[B" -> "byte[][]".
239         // To make life easier, we make primitives look like unqualified
240         // reference types.
241         switch (*c) {
242         case 'B': c = "byte;"; break;
243         case 'C': c = "char;"; break;
244         case 'D': c = "double;"; break;
245         case 'F': c = "float;"; break;
246         case 'I': c = "int;"; break;
247         case 'J': c = "long;"; break;
248         case 'S': c = "short;"; break;
249         case 'Z': c = "boolean;"; break;
250         default: return strdup(descriptor);
251         }
252         resultLength = strlen(c) - 1 + 2*dim;
253     }
254
255     // Allocate enough space.
256     char* result = (char*)malloc(resultLength + 1);
257     if (result == NULL) {
258         return NULL;
259     }
260
261     // At this point, 'c' is a string of the form "fully/qualified/Type;"
262     // or "primitive;". Rewrite the type with '.' instead of '/':
263     const char* p = c;
264     char* q = result;
265     while (*p != ';') {
266         char ch = *p++;
267         if (ch == '/') {
268           ch = '.';
269         }
270         *q++ = ch;
271     }
272     // ...and replace the semicolon with 'dim' "[]" pairs:
273     while (dim--) {
274         *q++ = '[';
275         *q++ = ']';
276     }
277     *q = '\0';
278     return result;
279 }
280
281 /*
282  * Return a newly-allocated string for the "dot version" of the class
283  * name for the given type descriptor. That is, The initial "L" and
284  * final ";" (if any) have been removed and all occurrences of '/'
285  * have been changed to '.'.
286  *
287  * "Dot version" names are used in the class loading machinery.
288  * See also dvmHumanReadableDescriptor.
289  */
290 char* dvmDescriptorToDot(const char* str)
291 {
292     size_t at = strlen(str);
293     char* newStr;
294
295     if ((at >= 2) && (str[0] == 'L') && (str[at - 1] == ';')) {
296         at -= 2; /* Two fewer chars to copy. */
297         str++; /* Skip the 'L'. */
298     }
299
300     newStr = (char*)malloc(at + 1); /* Add one for the '\0'. */
301     if (newStr == NULL)
302         return NULL;
303
304     newStr[at] = '\0';
305
306     while (at > 0) {
307         at--;
308         newStr[at] = (str[at] == '/') ? '.' : str[at];
309     }
310
311     return newStr;
312 }
313
314 /*
315  * Return a newly-allocated string for the type descriptor
316  * corresponding to the "dot version" of the given class name. That
317  * is, non-array names are surrounded by "L" and ";", and all
318  * occurrences of '.' have been changed to '/'.
319  *
320  * "Dot version" names are used in the class loading machinery.
321  */
322 char* dvmDotToDescriptor(const char* str)
323 {
324     size_t length = strlen(str);
325     int wrapElSemi = 0;
326     char* newStr;
327     char* at;
328
329     if (str[0] != '[') {
330         length += 2; /* for "L" and ";" */
331         wrapElSemi = 1;
332     }
333
334     newStr = at = (char*)malloc(length + 1); /* + 1 for the '\0' */
335
336     if (newStr == NULL) {
337         return NULL;
338     }
339
340     if (wrapElSemi) {
341         *(at++) = 'L';
342     }
343
344     while (*str) {
345         char c = *(str++);
346         if (c == '.') {
347             c = '/';
348         }
349         *(at++) = c;
350     }
351
352     if (wrapElSemi) {
353         *(at++) = ';';
354     }
355
356     *at = '\0';
357     return newStr;
358 }
359
360 /*
361  * Return a newly-allocated string for the internal-form class name for
362  * the given type descriptor. That is, the initial "L" and final ";" (if
363  * any) have been removed.
364  */
365 char* dvmDescriptorToName(const char* str)
366 {
367     if (str[0] == 'L') {
368         size_t length = strlen(str) - 1;
369         char* newStr = (char*)malloc(length);
370
371         if (newStr == NULL) {
372             return NULL;
373         }
374
375         strlcpy(newStr, str + 1, length);
376         return newStr;
377     }
378
379     return strdup(str);
380 }
381
382 /*
383  * Return a newly-allocated string for the type descriptor for the given
384  * internal-form class name. That is, a non-array class name will get
385  * surrounded by "L" and ";", while array names are left as-is.
386  */
387 char* dvmNameToDescriptor(const char* str)
388 {
389     if (str[0] != '[') {
390         size_t length = strlen(str);
391         char* descriptor = (char*)malloc(length + 3);
392
393         if (descriptor == NULL) {
394             return NULL;
395         }
396
397         descriptor[0] = 'L';
398         strcpy(descriptor + 1, str);
399         descriptor[length + 1] = ';';
400         descriptor[length + 2] = '\0';
401
402         return descriptor;
403     }
404
405     return strdup(str);
406 }
407
408 /*
409  * Get a notion of the current time, in nanoseconds.  This is meant for
410  * computing durations (e.g. "operation X took 52nsec"), so the result
411  * should not be used to get the current date/time.
412  */
413 u8 dvmGetRelativeTimeNsec()
414 {
415 #ifdef HAVE_POSIX_CLOCKS
416     struct timespec now;
417     clock_gettime(CLOCK_MONOTONIC, &now);
418     return (u8)now.tv_sec*1000000000LL + now.tv_nsec;
419 #else
420     struct timeval now;
421     gettimeofday(&now, NULL);
422     return (u8)now.tv_sec*1000000000LL + now.tv_usec * 1000LL;
423 #endif
424 }
425
426 /*
427  * Get the per-thread CPU time, in nanoseconds.
428  *
429  * Only useful for time deltas.
430  */
431 u8 dvmGetThreadCpuTimeNsec()
432 {
433 #ifdef HAVE_POSIX_CLOCKS
434     struct timespec now;
435     clock_gettime(CLOCK_THREAD_CPUTIME_ID, &now);
436     return (u8)now.tv_sec*1000000000LL + now.tv_nsec;
437 #else
438     return (u8) -1;
439 #endif
440 }
441
442 /*
443  * Get the per-thread CPU time, in nanoseconds, for the specified thread.
444  */
445 u8 dvmGetOtherThreadCpuTimeNsec(pthread_t thread)
446 {
447 #if 0 /*def HAVE_POSIX_CLOCKS*/
448     int clockId;
449
450     if (pthread_getcpuclockid(thread, &clockId) != 0)
451         return (u8) -1;
452
453     struct timespec now;
454     clock_gettime(clockId, &now);
455     return (u8)now.tv_sec*1000000000LL + now.tv_nsec;
456 #else
457     return (u8) -1;
458 #endif
459 }
460
461
462 /*
463  * Call this repeatedly, with successively higher values for "iteration",
464  * to sleep for a period of time not to exceed "maxTotalSleep".
465  *
466  * For example, when called with iteration==0 we will sleep for a very
467  * brief time.  On the next call we will sleep for a longer time.  When
468  * the sum total of all sleeps reaches "maxTotalSleep", this returns false.
469  *
470  * The initial start time value for "relStartTime" MUST come from the
471  * dvmGetRelativeTimeUsec call.  On the device this must come from the
472  * monotonic clock source, not the wall clock.
473  *
474  * This should be used wherever you might be tempted to call sched_yield()
475  * in a loop.  The problem with sched_yield is that, for a high-priority
476  * thread, the kernel might not actually transfer control elsewhere.
477  *
478  * Returns "false" if we were unable to sleep because our time was up.
479  */
480 bool dvmIterativeSleep(int iteration, int maxTotalSleep, u8 relStartTime)
481 {
482     const int minSleep = 10000;
483     u8 curTime;
484     int curDelay;
485
486     /*
487      * Get current time, and see if we've already exceeded the limit.
488      */
489     curTime = dvmGetRelativeTimeUsec();
490     if (curTime >= relStartTime + maxTotalSleep) {
491         LOGVV("exsl: sleep exceeded (start=%llu max=%d now=%llu)\n",
492             relStartTime, maxTotalSleep, curTime);
493         return false;
494     }
495
496     /*
497      * Compute current delay.  We're bounded by "maxTotalSleep", so no
498      * real risk of overflow assuming "usleep" isn't returning early.
499      * (Besides, 2^30 usec is about 18 minutes by itself.)
500      *
501      * For iteration==0 we just call sched_yield(), so the first sleep
502      * at iteration==1 is actually (minSleep * 2).
503      */
504     curDelay = minSleep;
505     while (iteration-- > 0)
506         curDelay *= 2;
507     assert(curDelay > 0);
508
509     if (curTime + curDelay >= relStartTime + maxTotalSleep) {
510         LOGVV("exsl: reduced delay from %d to %d\n",
511             curDelay, (int) ((relStartTime + maxTotalSleep) - curTime));
512         curDelay = (int) ((relStartTime + maxTotalSleep) - curTime);
513     }
514
515     if (iteration == 0) {
516         LOGVV("exsl: yield\n");
517         sched_yield();
518     } else {
519         LOGVV("exsl: sleep for %d\n", curDelay);
520         usleep(curDelay);
521     }
522     return true;
523 }
524
525
526 /*
527  * Set the "close on exec" flag so we don't expose our file descriptors
528  * to processes launched by us.
529  */
530 bool dvmSetCloseOnExec(int fd)
531 {
532     int flags;
533
534     /*
535      * There's presently only one flag defined, so getting the previous
536      * value of the fd flags is probably unnecessary.
537      */
538     flags = fcntl(fd, F_GETFD);
539     if (flags < 0) {
540         LOGW("Unable to get fd flags for fd %d\n", fd);
541         return false;
542     }
543     if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) {
544         LOGW("Unable to set close-on-exec for fd %d\n", fd);
545         return false;
546     }
547     return true;
548 }
549
550 #if (!HAVE_STRLCPY)
551 /* Implementation of strlcpy() for platforms that don't already have it. */
552 size_t strlcpy(char *dst, const char *src, size_t size) {
553     size_t srcLength = strlen(src);
554     size_t copyLength = srcLength;
555
556     if (srcLength > (size - 1)) {
557         copyLength = size - 1;
558     }
559
560     if (size != 0) {
561         strncpy(dst, src, copyLength);
562         dst[copyLength] = '\0';
563     }
564
565     return srcLength;
566 }
567 #endif
568
569 /*
570  *  Allocates a memory region using ashmem and mmap, initialized to
571  *  zero.  Actual allocation rounded up to page multiple.  Returns
572  *  NULL on failure.
573  */
574 void *dvmAllocRegion(size_t byteCount, int prot, const char *name) {
575     void *base;
576     int fd, ret;
577
578     byteCount = ALIGN_UP_TO_PAGE_SIZE(byteCount);
579     fd = ashmem_create_region(name, byteCount);
580     if (fd == -1) {
581         return NULL;
582     }
583     base = mmap(NULL, byteCount, prot, MAP_PRIVATE, fd, 0);
584     ret = close(fd);
585     if (base == MAP_FAILED) {
586         return NULL;
587     }
588     if (ret == -1) {
589         return NULL;
590     }
591     return base;
592 }
593
594 /*
595  * Get some per-thread stats.
596  *
597  * This is currently generated by opening the appropriate "stat" file
598  * in /proc and reading the pile of stuff that comes out.
599  */
600 bool dvmGetThreadStats(ProcStatData* pData, pid_t tid)
601 {
602     /*
603     int pid;
604     char comm[128];
605     char state;
606     int ppid, pgrp, session, tty_nr, tpgid;
607     unsigned long flags, minflt, cminflt, majflt, cmajflt, utime, stime;
608     long cutime, cstime, priority, nice, zero, itrealvalue;
609     unsigned long starttime, vsize;
610     long rss;
611     unsigned long rlim, startcode, endcode, startstack, kstkesp, kstkeip;
612     unsigned long signal, blocked, sigignore, sigcatch, wchan, nswap, cnswap;
613     int exit_signal, processor;
614     unsigned long rt_priority, policy;
615
616     scanf("%d %s %c %d %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %ld %ld %ld "
617           "%ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu "
618           "%lu %lu %lu %d %d %lu %lu",
619         &pid, comm, &state, &ppid, &pgrp, &session, &tty_nr, &tpgid,
620         &flags, &minflt, &cminflt, &majflt, &cmajflt, &utime, &stime,
621         &cutime, &cstime, &priority, &nice, &zero, &itrealvalue,
622         &starttime, &vsize, &rss, &rlim, &startcode, &endcode,
623         &startstack, &kstkesp, &kstkeip, &signal, &blocked, &sigignore,
624         &sigcatch, &wchan, &nswap, &cnswap, &exit_signal, &processor,
625         &rt_priority, &policy);
626
627         (new: delayacct_blkio_ticks %llu (since Linux 2.6.18))
628     */
629
630     char nameBuf[64];
631     int i, fd;
632
633     /*
634      * Open and read the appropriate file.  This is expected to work on
635      * Linux but will fail on other platforms (e.g. Mac sim).
636      */
637     sprintf(nameBuf, "/proc/self/task/%d/stat", (int) tid);
638     fd = open(nameBuf, O_RDONLY);
639     if (fd < 0) {
640         LOGV("Unable to open '%s': %s\n", nameBuf, strerror(errno));
641         return false;
642     }
643
644     char lineBuf[512];      /* > 2x typical */
645     int cc = read(fd, lineBuf, sizeof(lineBuf)-1);
646     if (cc <= 0) {
647         const char* msg = (cc == 0) ? "unexpected EOF" : strerror(errno);
648         LOGI("Unable to read '%s': %s\n", nameBuf, msg);
649         close(fd);
650         return false;
651     }
652     close(fd);
653     lineBuf[cc] = '\0';
654
655     /*
656      * Skip whitespace-separated tokens.  For the most part we can assume
657      * that tokens do not contain spaces, and are separated by exactly one
658      * space character.  The only exception is the second field ("comm")
659      * which may contain spaces but is surrounded by parenthesis.
660      */
661     char* cp = strchr(lineBuf, ')');
662     if (cp == NULL)
663         goto parse_fail;
664     cp++;
665     for (i = 2; i < 13; i++) {
666         cp = strchr(cp+1, ' ');
667         if (cp == NULL)
668             goto parse_fail;
669     }
670
671     /*
672      * Grab utime/stime.
673      */
674     char* endp;
675     pData->utime = strtoul(cp+1, &endp, 10);
676     if (endp == cp+1)
677         LOGI("Warning: strtoul failed on utime ('%.30s...')\n", cp);
678
679     cp = strchr(cp+1, ' ');
680     if (cp == NULL)
681         goto parse_fail;
682
683     pData->stime = strtoul(cp+1, &endp, 10);
684     if (endp == cp+1)
685         LOGI("Warning: strtoul failed on stime ('%.30s...')\n", cp);
686
687     /*
688      * Skip more stuff we don't care about.
689      */
690     for (i = 14; i < 38; i++) {
691         cp = strchr(cp+1, ' ');
692         if (cp == NULL)
693             goto parse_fail;
694     }
695
696     /*
697      * Grab processor number.
698      */
699     pData->processor = strtol(cp+1, &endp, 10);
700     if (endp == cp+1)
701         LOGI("Warning: strtoul failed on processor ('%.30s...')\n", cp);
702
703     return true;
704
705 parse_fail:
706     LOGI("stat parse failed (%s)\n", lineBuf);
707     return false;
708 }
709
710 /* documented in header file */
711 const char* dvmPathToAbsolutePortion(const char* path) {
712     if (path == NULL) {
713         return NULL;
714     }
715
716     if (path[0] == '/') {
717         /* It's a regular absolute path. Return it. */
718         return path;
719     }
720
721     const char* sentinel = strstr(path, "/./");
722
723     if (sentinel != NULL) {
724         /* It's got the sentinel. Return a pointer to the second slash. */
725         return sentinel + 2;
726     }
727
728     return NULL;
729 }