diff options
author | Brian Carlstrom <bdc@google.com> | 2014-08-05 12:46:17 -0700 |
---|---|---|
committer | Brian Carlstrom <bdc@google.com> | 2014-08-05 12:51:13 -0700 |
commit | 870b4f2d70d67d6dbb7d0881d101c61bed8caad2 (patch) | |
tree | 7487dad3970556a040f88a49852a3dc9ed19bebd /vm/Misc.cpp | |
parent | 76e15e367ae1189b6f641ba8d16ca92bd179dac0 (diff) | |
download | android_dalvik-870b4f2d70d67d6dbb7d0881d101c61bed8caad2.tar.gz android_dalvik-870b4f2d70d67d6dbb7d0881d101c61bed8caad2.tar.bz2 android_dalvik-870b4f2d70d67d6dbb7d0881d101c61bed8caad2.zip |
Dalvik is dead, long live Dalvik!
croot
cd dalvik
repo start dalvik-is-dead-long-live-dalvik .
repo sync -c .
git rm -r README.txt
git rm -r dexopt
git rm -r tools/deadcode.py
git rm -r tools/dex-preopt
git rm -r tools/dexcheck
git rm -r tools/gdbjithelper
git rm -r unit-tests
git rm -r vm
git checkout HEAD vm/Common.h (needed by libdex)
git checkout HEAD vm/DalvikVersion.h (needed by libdex)
git checkout HEAD vm/Profile.h (needed by dmtracedump)
git add Android.mk (after removing vm, dexopt, and unit-tests references)
git commit -a -m 'Dalvik is dead, long live Dalvik!'
Bug: 14298175
Change-Id: I9dd13053677629d13496d4238af4374452cda415
Diffstat (limited to 'vm/Misc.cpp')
-rw-r--r-- | vm/Misc.cpp | 832 |
1 files changed, 0 insertions, 832 deletions
diff --git a/vm/Misc.cpp b/vm/Misc.cpp deleted file mode 100644 index 057b90d6d..000000000 --- a/vm/Misc.cpp +++ /dev/null @@ -1,832 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Miscellaneous utility functions. - */ -#include "Dalvik.h" - -#include <stdlib.h> -#include <stddef.h> -#include <string.h> -#include <strings.h> -#include <ctype.h> -#include <time.h> -#include <sys/time.h> -#include <fcntl.h> -#include <cutils/ashmem.h> -#include <sys/mman.h> - -/* - * Print a hex dump in this format: - * -01234567: 00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff 0123456789abcdef\n - * - * If "mode" is kHexDumpLocal, we start at offset zero, and show a full - * 16 bytes on the first line. If it's kHexDumpMem, we make this look - * like a memory dump, using the actual address, outputting a partial line - * if "vaddr" isn't aligned on a 16-byte boundary. - * - * "priority" and "tag" determine the values passed to the log calls. - * - * Does not use printf() or other string-formatting calls. - */ -void dvmPrintHexDumpEx(int priority, const char* tag, const void* vaddr, - size_t length, HexDumpMode mode) -{ - static const char gHexDigit[] = "0123456789abcdef"; - const unsigned char* addr = (const unsigned char*)vaddr; - char out[77]; /* exact fit */ - unsigned int offset; /* offset to show while printing */ - char* hex; - char* asc; - int gap; - //int trickle = 0; - - if (mode == kHexDumpLocal) - offset = 0; - else - offset = (int) addr; - - memset(out, ' ', sizeof(out)-1); - out[8] = ':'; - out[sizeof(out)-2] = '\n'; - out[sizeof(out)-1] = '\0'; - - gap = (int) offset & 0x0f; - while (length) { - unsigned int lineOffset = offset & ~0x0f; - int i, count; - - hex = out; - asc = out + 59; - - for (i = 0; i < 8; i++) { - *hex++ = gHexDigit[lineOffset >> 28]; - lineOffset <<= 4; - } - hex++; - hex++; - - count = ((int)length > 16-gap) ? 16-gap : (int)length; /* cap length */ - assert(count != 0); - assert(count+gap <= 16); - - if (gap) { - /* only on first line */ - hex += gap * 3; - asc += gap; - } - - for (i = gap ; i < count+gap; i++) { - *hex++ = gHexDigit[*addr >> 4]; - *hex++ = gHexDigit[*addr & 0x0f]; - hex++; - if (*addr >= 0x20 && *addr < 0x7f /*isprint(*addr)*/) - *asc++ = *addr; - else - *asc++ = '.'; - addr++; - } - for ( ; i < 16; i++) { - /* erase extra stuff; only happens on last line */ - *hex++ = ' '; - *hex++ = ' '; - hex++; - *asc++ = ' '; - } - - LOG_PRI(priority, tag, "%s", out); -#if 0 //def HAVE_ANDROID_OS - /* - * We can overrun logcat easily by writing at full speed. On the - * other hand, we can make Eclipse time out if we're showing - * packet dumps while debugging JDWP. - */ - { - if (trickle++ == 8) { - trickle = 0; - usleep(20000); - } - } -#endif - - gap = 0; - length -= count; - offset += count; - } -} - - -/* - * Fill out a DebugOutputTarget, suitable for printing to the log. - */ -void dvmCreateLogOutputTarget(DebugOutputTarget* target, int priority, - const char* tag) -{ - assert(target != NULL); - assert(tag != NULL); - - target->which = kDebugTargetLog; - target->data.log.priority = priority; - target->data.log.tag = tag; -} - -/* - * Fill out a DebugOutputTarget suitable for printing to a file pointer. - */ -void dvmCreateFileOutputTarget(DebugOutputTarget* target, FILE* fp) -{ - assert(target != NULL); - assert(fp != NULL); - - target->which = kDebugTargetFile; - target->data.file.fp = fp; -} - -/* - * Free "target" and any associated data. - */ -void dvmFreeOutputTarget(DebugOutputTarget* target) -{ - free(target); -} - -/* - * Print a debug message, to either a file or the log. - */ -void dvmPrintDebugMessage(const DebugOutputTarget* target, const char* format, - ...) -{ - va_list args; - - va_start(args, format); - - switch (target->which) { - case kDebugTargetLog: - LOG_PRI_VA(target->data.log.priority, target->data.log.tag, - format, args); - break; - case kDebugTargetFile: - vfprintf(target->data.file.fp, format, args); - break; - default: - ALOGE("unexpected 'which' %d", target->which); - break; - } - - va_end(args); -} - - -/* - * Return a newly-allocated string in which all occurrences of '.' have - * been changed to '/'. If we find a '/' in the original string, NULL - * is returned to avoid ambiguity. - */ -char* dvmDotToSlash(const char* str) -{ - char* newStr = strdup(str); - char* cp = newStr; - - if (newStr == NULL) - return NULL; - - while (*cp != '\0') { - if (*cp == '/') { - assert(false); - return NULL; - } - if (*cp == '.') - *cp = '/'; - cp++; - } - - return newStr; -} - -std::string dvmHumanReadableDescriptor(const char* descriptor) { - // Count the number of '['s to get the dimensionality. - const char* c = descriptor; - size_t dim = 0; - while (*c == '[') { - dim++; - c++; - } - - // Reference or primitive? - if (*c == 'L') { - // "[[La/b/C;" -> "a.b.C[][]". - c++; // Skip the 'L'. - } else { - // "[[B" -> "byte[][]". - // To make life easier, we make primitives look like unqualified - // reference types. - switch (*c) { - case 'B': c = "byte;"; break; - case 'C': c = "char;"; break; - case 'D': c = "double;"; break; - case 'F': c = "float;"; break; - case 'I': c = "int;"; break; - case 'J': c = "long;"; break; - case 'S': c = "short;"; break; - case 'Z': c = "boolean;"; break; - default: return descriptor; - } - } - - // At this point, 'c' is a string of the form "fully/qualified/Type;" - // or "primitive;". Rewrite the type with '.' instead of '/': - std::string result; - const char* p = c; - while (*p != ';') { - char ch = *p++; - if (ch == '/') { - ch = '.'; - } - result.push_back(ch); - } - // ...and replace the semicolon with 'dim' "[]" pairs: - while (dim--) { - result += "[]"; - } - return result; -} - -std::string dvmHumanReadableType(const Object* obj) -{ - if (obj == NULL) { - return "null"; - } - if (obj->clazz == NULL) { - /* should only be possible right after a plain dvmMalloc() */ - return "(raw)"; - } - std::string result(dvmHumanReadableDescriptor(obj->clazz->descriptor)); - if (dvmIsClassObject(obj)) { - const ClassObject* clazz = reinterpret_cast<const ClassObject*>(obj); - result += "<" + dvmHumanReadableDescriptor(clazz->descriptor) + ">"; - } - return result; -} - -std::string dvmHumanReadableField(const Field* field) -{ - if (field == NULL) { - return "(null)"; - } - std::string result(dvmHumanReadableDescriptor(field->clazz->descriptor)); - result += '.'; - result += field->name; - return result; -} - -std::string dvmHumanReadableMethod(const Method* method, bool withSignature) -{ - if (method == NULL) { - return "(null)"; - } - std::string result(dvmHumanReadableDescriptor(method->clazz->descriptor)); - result += '.'; - result += method->name; - if (withSignature) { - // TODO: the types in this aren't human readable! - char* signature = dexProtoCopyMethodDescriptor(&method->prototype); - result += signature; - free(signature); - } - return result; -} - -/* - * Return a newly-allocated string for the "dot version" of the class - * name for the given type descriptor. That is, The initial "L" and - * final ";" (if any) have been removed and all occurrences of '/' - * have been changed to '.'. - * - * "Dot version" names are used in the class loading machinery. - * See also dvmHumanReadableDescriptor. - */ -char* dvmDescriptorToDot(const char* str) -{ - size_t at = strlen(str); - char* newStr; - - if ((at >= 2) && (str[0] == 'L') && (str[at - 1] == ';')) { - at -= 2; /* Two fewer chars to copy. */ - str++; /* Skip the 'L'. */ - } - - newStr = (char*)malloc(at + 1); /* Add one for the '\0'. */ - if (newStr == NULL) - return NULL; - - newStr[at] = '\0'; - - while (at > 0) { - at--; - newStr[at] = (str[at] == '/') ? '.' : str[at]; - } - - return newStr; -} - -/* - * Return a newly-allocated string for the type descriptor - * corresponding to the "dot version" of the given class name. That - * is, non-array names are surrounded by "L" and ";", and all - * occurrences of '.' have been changed to '/'. - * - * "Dot version" names are used in the class loading machinery. - */ -char* dvmDotToDescriptor(const char* str) -{ - size_t length = strlen(str); - int wrapElSemi = 0; - char* newStr; - char* at; - - if (str[0] != '[') { - length += 2; /* for "L" and ";" */ - wrapElSemi = 1; - } - - newStr = at = (char*)malloc(length + 1); /* + 1 for the '\0' */ - - if (newStr == NULL) { - return NULL; - } - - if (wrapElSemi) { - *(at++) = 'L'; - } - - while (*str) { - char c = *(str++); - if (c == '.') { - c = '/'; - } - *(at++) = c; - } - - if (wrapElSemi) { - *(at++) = ';'; - } - - *at = '\0'; - return newStr; -} - -/* - * Return a newly-allocated string for the internal-form class name for - * the given type descriptor. That is, the initial "L" and final ";" (if - * any) have been removed. - */ -char* dvmDescriptorToName(const char* str) -{ - if (str[0] == 'L') { - size_t length = strlen(str) - 1; - char* newStr = (char*)malloc(length); - - if (newStr == NULL) { - return NULL; - } - - strlcpy(newStr, str + 1, length); - return newStr; - } - - return strdup(str); -} - -/* - * Return a newly-allocated string for the type descriptor for the given - * internal-form class name. That is, a non-array class name will get - * surrounded by "L" and ";", while array names are left as-is. - */ -char* dvmNameToDescriptor(const char* str) -{ - if (str[0] != '[') { - size_t length = strlen(str); - char* descriptor = (char*)malloc(length + 3); - - if (descriptor == NULL) { - return NULL; - } - - descriptor[0] = 'L'; - strcpy(descriptor + 1, str); - descriptor[length + 1] = ';'; - descriptor[length + 2] = '\0'; - - return descriptor; - } - - return strdup(str); -} - -/* - * Get a notion of the current time, in nanoseconds. This is meant for - * computing durations (e.g. "operation X took 52nsec"), so the result - * should not be used to get the current date/time. - */ -u8 dvmGetRelativeTimeNsec() -{ -#ifdef HAVE_POSIX_CLOCKS - struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - return (u8)now.tv_sec*1000000000LL + now.tv_nsec; -#else - struct timeval now; - gettimeofday(&now, NULL); - return (u8)now.tv_sec*1000000000LL + now.tv_usec * 1000LL; -#endif -} - -/* - * Get the per-thread CPU time, in nanoseconds. - * - * Only useful for time deltas. - */ -u8 dvmGetThreadCpuTimeNsec() -{ -#ifdef HAVE_POSIX_CLOCKS - struct timespec now; - clock_gettime(CLOCK_THREAD_CPUTIME_ID, &now); - return (u8)now.tv_sec*1000000000LL + now.tv_nsec; -#else - return (u8) -1; -#endif -} - -/* - * Get the per-thread CPU time, in nanoseconds, for the specified thread. - */ -u8 dvmGetOtherThreadCpuTimeNsec(pthread_t thread) -{ -#if 0 /*def HAVE_POSIX_CLOCKS*/ - int clockId; - - if (pthread_getcpuclockid(thread, &clockId) != 0) - return (u8) -1; - - struct timespec now; - clock_gettime(clockId, &now); - return (u8)now.tv_sec*1000000000LL + now.tv_nsec; -#else - return (u8) -1; -#endif -} - - -/* - * Call this repeatedly, with successively higher values for "iteration", - * to sleep for a period of time not to exceed "maxTotalSleep". - * - * For example, when called with iteration==0 we will sleep for a very - * brief time. On the next call we will sleep for a longer time. When - * the sum total of all sleeps reaches "maxTotalSleep", this returns false. - * - * The initial start time value for "relStartTime" MUST come from the - * dvmGetRelativeTimeUsec call. On the device this must come from the - * monotonic clock source, not the wall clock. - * - * This should be used wherever you might be tempted to call sched_yield() - * in a loop. The problem with sched_yield is that, for a high-priority - * thread, the kernel might not actually transfer control elsewhere. - * - * Returns "false" if we were unable to sleep because our time was up. - */ -bool dvmIterativeSleep(int iteration, int maxTotalSleep, u8 relStartTime) -{ - /* - * Minimum sleep is one millisecond, it is important to keep this value - * low to ensure short GC pauses since dvmSuspendAllThreads() uses this - * function. - */ - const int minSleep = 1000; - u8 curTime; - int curDelay; - - /* - * Get current time, and see if we've already exceeded the limit. - */ - curTime = dvmGetRelativeTimeUsec(); - if (curTime >= relStartTime + maxTotalSleep) { - LOGVV("exsl: sleep exceeded (start=%llu max=%d now=%llu)", - relStartTime, maxTotalSleep, curTime); - return false; - } - - /* - * Compute current delay. We're bounded by "maxTotalSleep", so no - * real risk of overflow assuming "usleep" isn't returning early. - * (Besides, 2^30 usec is about 18 minutes by itself.) - * - * For iteration==0 we just call sched_yield(), so the first sleep - * at iteration==1 is actually (minSleep * 2). - */ - curDelay = minSleep; - while (iteration-- > 0) - curDelay *= 2; - assert(curDelay > 0); - - if (curTime + curDelay >= relStartTime + maxTotalSleep) { - LOGVV("exsl: reduced delay from %d to %d", - curDelay, (int) ((relStartTime + maxTotalSleep) - curTime)); - curDelay = (int) ((relStartTime + maxTotalSleep) - curTime); - } - - if (iteration == 0) { - LOGVV("exsl: yield"); - sched_yield(); - } else { - LOGVV("exsl: sleep for %d", curDelay); - usleep(curDelay); - } - return true; -} - - -/* - * Set the "close on exec" flag so we don't expose our file descriptors - * to processes launched by us. - */ -bool dvmSetCloseOnExec(int fd) -{ - int flags; - - /* - * There's presently only one flag defined, so getting the previous - * value of the fd flags is probably unnecessary. - */ - flags = fcntl(fd, F_GETFD); - if (flags < 0) { - ALOGW("Unable to get fd flags for fd %d", fd); - return false; - } - if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) { - ALOGW("Unable to set close-on-exec for fd %d", fd); - return false; - } - return true; -} - -#if (!HAVE_STRLCPY) -/* Implementation of strlcpy() for platforms that don't already have it. */ -size_t strlcpy(char *dst, const char *src, size_t size) { - size_t srcLength = strlen(src); - size_t copyLength = srcLength; - - if (srcLength > (size - 1)) { - copyLength = size - 1; - } - - if (size != 0) { - strncpy(dst, src, copyLength); - dst[copyLength] = '\0'; - } - - return srcLength; -} -#endif - -/* - * Allocates a memory region using ashmem and mmap, initialized to - * zero. Actual allocation rounded up to page multiple. Returns - * NULL on failure. - */ -void *dvmAllocRegion(size_t byteCount, int prot, const char *name) { - void *base; - int fd, ret; - - byteCount = ALIGN_UP_TO_PAGE_SIZE(byteCount); - fd = ashmem_create_region(name, byteCount); - if (fd == -1) { - return NULL; - } - base = mmap(NULL, byteCount, prot, MAP_PRIVATE, fd, 0); - ret = close(fd); - if (base == MAP_FAILED) { - return NULL; - } - if (ret == -1) { - munmap(base, byteCount); - return NULL; - } - return base; -} - -/* - * Get some per-thread stats. - * - * This is currently generated by opening the appropriate "stat" file - * in /proc and reading the pile of stuff that comes out. - */ -bool dvmGetThreadStats(ProcStatData* pData, pid_t tid) -{ - /* - int pid; - char comm[128]; - char state; - int ppid, pgrp, session, tty_nr, tpgid; - unsigned long flags, minflt, cminflt, majflt, cmajflt, utime, stime; - long cutime, cstime, priority, nice, zero, itrealvalue; - unsigned long starttime, vsize; - long rss; - unsigned long rlim, startcode, endcode, startstack, kstkesp, kstkeip; - unsigned long signal, blocked, sigignore, sigcatch, wchan, nswap, cnswap; - int exit_signal, processor; - unsigned long rt_priority, policy; - - scanf("%d %s %c %d %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %ld %ld %ld " - "%ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu " - "%lu %lu %lu %d %d %lu %lu", - &pid, comm, &state, &ppid, &pgrp, &session, &tty_nr, &tpgid, - &flags, &minflt, &cminflt, &majflt, &cmajflt, &utime, &stime, - &cutime, &cstime, &priority, &nice, &zero, &itrealvalue, - &starttime, &vsize, &rss, &rlim, &startcode, &endcode, - &startstack, &kstkesp, &kstkeip, &signal, &blocked, &sigignore, - &sigcatch, &wchan, &nswap, &cnswap, &exit_signal, &processor, - &rt_priority, &policy); - - (new: delayacct_blkio_ticks %llu (since Linux 2.6.18)) - */ - - char nameBuf[64]; - int i, fd; - - /* - * Open and read the appropriate file. This is expected to work on - * Linux but will fail on other platforms (e.g. Mac sim). - */ - sprintf(nameBuf, "/proc/self/task/%d/stat", (int) tid); - fd = open(nameBuf, O_RDONLY); - if (fd < 0) { - ALOGV("Unable to open '%s': %s", nameBuf, strerror(errno)); - return false; - } - - char lineBuf[512]; /* > 2x typical */ - int cc = read(fd, lineBuf, sizeof(lineBuf)-1); - if (cc <= 0) { - const char* msg = (cc == 0) ? "unexpected EOF" : strerror(errno); - ALOGI("Unable to read '%s': %s", nameBuf, msg); - close(fd); - return false; - } - close(fd); - lineBuf[cc] = '\0'; - - /* - * Skip whitespace-separated tokens. For the most part we can assume - * that tokens do not contain spaces, and are separated by exactly one - * space character. The only exception is the second field ("comm") - * which may contain spaces but is surrounded by parenthesis. - */ - char* cp = strchr(lineBuf, ')'); - if (cp == NULL) - goto parse_fail; - cp += 2; - pData->state = *cp++; - - for (i = 3; i < 13; i++) { - cp = strchr(cp+1, ' '); - if (cp == NULL) - goto parse_fail; - } - - /* - * Grab utime/stime. - */ - char* endp; - pData->utime = strtoul(cp+1, &endp, 10); - if (endp == cp+1) - ALOGI("Warning: strtoul failed on utime ('%.30s...')", cp); - - cp = strchr(cp+1, ' '); - if (cp == NULL) - goto parse_fail; - - pData->stime = strtoul(cp+1, &endp, 10); - if (endp == cp+1) - ALOGI("Warning: strtoul failed on stime ('%.30s...')", cp); - - /* - * Skip more stuff we don't care about. - */ - for (i = 14; i < 38; i++) { - cp = strchr(cp+1, ' '); - if (cp == NULL) - goto parse_fail; - } - - /* - * Grab processor number. - */ - pData->processor = strtol(cp+1, &endp, 10); - if (endp == cp+1) - ALOGI("Warning: strtoul failed on processor ('%.30s...')", cp); - - return true; - -parse_fail: - ALOGI("stat parse failed (%s)", lineBuf); - return false; -} - -/* documented in header file */ -const char* dvmPathToAbsolutePortion(const char* path) { - if (path == NULL) { - return NULL; - } - - if (path[0] == '/') { - /* It's a regular absolute path. Return it. */ - return path; - } - - const char* sentinel = strstr(path, "/./"); - - if (sentinel != NULL) { - /* It's got the sentinel. Return a pointer to the second slash. */ - return sentinel + 2; - } - - return NULL; -} - -// From RE2. -void StringAppendV(std::string* dst, const char* format, va_list ap) { - // First try with a small fixed size buffer - char space[1024]; - - // It's possible for methods that use a va_list to invalidate - // the data in it upon use. The fix is to make a copy - // of the structure before using it and use that copy instead. - va_list backup_ap; - va_copy(backup_ap, ap); - int result = vsnprintf(space, sizeof(space), format, backup_ap); - va_end(backup_ap); - - if ((result >= 0) && ((size_t) result < sizeof(space))) { - // It fit - dst->append(space, result); - return; - } - - // Repeatedly increase buffer size until it fits - int length = sizeof(space); - while (true) { - if (result < 0) { - // Older behavior: just try doubling the buffer size - length *= 2; - } else { - // We need exactly "result+1" characters - length = result+1; - } - char* buf = new char[length]; - - // Restore the va_list before we use it again - va_copy(backup_ap, ap); - result = vsnprintf(buf, length, format, backup_ap); - va_end(backup_ap); - - if ((result >= 0) && (result < length)) { - // It fit - dst->append(buf, result); - delete[] buf; - return; - } - delete[] buf; - } -} - -std::string StringPrintf(const char* fmt, ...) { - va_list ap; - va_start(ap, fmt); - std::string result; - StringAppendV(&result, fmt, ap); - va_end(ap); - return result; -} - -void StringAppendF(std::string* dst, const char* format, ...) { - va_list ap; - va_start(ap, format); - StringAppendV(dst, format, ap); - va_end(ap); -} |