subdirs := $(addprefix $(LOCAL_PATH)/,$(addsuffix /Android.mk, \
libdex \
vm \
- dalvikvm \
dexgen \
dexlist \
dexopt \
# ************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
# ************************************************
+$(call add-clean-step, rm -rf $(OUT)/obj/STATIC_LIBRARIES/libdex_intermediates/import_includes)
+++ /dev/null
-# 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.
-
-
-LOCAL_PATH:= $(call my-dir)
-
-#
-# Common definitions.
-#
-
-dalvikvm_src_files := \
- Main.cpp
-
-dalvikvm_c_includes := \
- dalvik/include
-
-
-#
-# Build for the target (device).
-#
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(dalvikvm_src_files)
-LOCAL_C_INCLUDES := $(dalvikvm_c_includes)
-
-LOCAL_SHARED_LIBRARIES := \
- libdvm \
- libssl \
- libz
-
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE := dalvikvm
-
-include $(BUILD_EXECUTABLE)
-
-
-#
-# Build for the host.
-#
-
-ifeq ($(WITH_HOST_DALVIK),true)
-
- include $(CLEAR_VARS)
- LOCAL_SRC_FILES := $(dalvikvm_src_files)
- LOCAL_C_INCLUDES := $(dalvikvm_c_includes)
-
- ifeq ($(HOST_OS)-$(HOST_ARCH),darwin-x86)
- # OS X comes with all these libraries, so there is no need
- # to build any of them. Note: OpenSSL consists of libssl
- # and libcrypto.
- LOCAL_LDLIBS := -lffi -lssl -lcrypto -lz
- else
- LOCAL_LDLIBS += -ldl -lpthread
- LOCAL_SHARED_LIBRARIES += libdvm libcrypto-host libicuuc-host libicui18n-host libssl-host
- endif
-
- LOCAL_MODULE_TAGS := optional
- LOCAL_MODULE := dalvikvm
-
- include $(BUILD_HOST_EXECUTABLE)
-
-endif
+++ /dev/null
-/*
- * 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.
- */
-/*
- * Command-line invocation of the Dalvik VM.
- */
-#include "jni.h"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <signal.h>
-#include <assert.h>
-
-
-/*
- * We want failed write() calls to just return with an error.
- */
-static void blockSigpipe()
-{
- sigset_t mask;
-
- sigemptyset(&mask);
- sigaddset(&mask, SIGPIPE);
- if (sigprocmask(SIG_BLOCK, &mask, NULL) != 0)
- fprintf(stderr, "WARNING: SIGPIPE not blocked\n");
-}
-
-/*
- * Create a String[] and populate it with the contents of argv.
- */
-static jobjectArray createStringArray(JNIEnv* env, char* const argv[], int argc)
-{
- jclass stringClass = NULL;
- jobjectArray strArray = NULL;
- jobjectArray result = NULL;
- int i;
-
- stringClass = env->FindClass("java/lang/String");
- if (env->ExceptionCheck()) {
- fprintf(stderr, "Got exception while finding class String\n");
- goto bail;
- }
- assert(stringClass != NULL);
- strArray = env->NewObjectArray(argc, stringClass, NULL);
- if (env->ExceptionCheck()) {
- fprintf(stderr, "Got exception while creating String array\n");
- goto bail;
- }
- assert(strArray != NULL);
-
- for (i = 0; i < argc; i++) {
- jstring argStr;
-
- argStr = env->NewStringUTF(argv[i]);
- if (env->ExceptionCheck()) {
- fprintf(stderr, "Got exception while allocating Strings\n");
- goto bail;
- }
- assert(argStr != NULL);
- env->SetObjectArrayElement(strArray, i, argStr);
- env->DeleteLocalRef(argStr);
- }
-
- /* return the array, and ensure we don't delete the local ref to it */
- result = strArray;
- strArray = NULL;
-
-bail:
- env->DeleteLocalRef(stringClass);
- env->DeleteLocalRef(strArray);
- return result;
-}
-
-/*
- * Determine whether or not the specified method is public.
- *
- * Returns JNI_TRUE on success, JNI_FALSE on failure.
- */
-static int methodIsPublic(JNIEnv* env, jclass clazz, jmethodID methodId)
-{
- static const int PUBLIC = 0x0001; // java.lang.reflect.Modifiers.PUBLIC
- jobject refMethod = NULL;
- jclass methodClass = NULL;
- jmethodID getModifiersId;
- int modifiers;
- int result = JNI_FALSE;
-
- refMethod = env->ToReflectedMethod(clazz, methodId, JNI_FALSE);
- if (refMethod == NULL) {
- fprintf(stderr, "Dalvik VM unable to get reflected method\n");
- goto bail;
- }
-
- /*
- * We now have a Method instance. We need to call
- * its getModifiers() method.
- */
- methodClass = env->FindClass("java/lang/reflect/Method");
- if (methodClass == NULL) {
- fprintf(stderr, "Dalvik VM unable to find class Method\n");
- goto bail;
- }
- getModifiersId = env->GetMethodID(methodClass,
- "getModifiers", "()I");
- if (getModifiersId == NULL) {
- fprintf(stderr, "Dalvik VM unable to find reflect.Method.getModifiers\n");
- goto bail;
- }
-
- modifiers = env->CallIntMethod(refMethod, getModifiersId);
- if ((modifiers & PUBLIC) == 0) {
- fprintf(stderr, "Dalvik VM: main() is not public\n");
- goto bail;
- }
-
- result = JNI_TRUE;
-
-bail:
- env->DeleteLocalRef(refMethod);
- env->DeleteLocalRef(methodClass);
- return result;
-}
-
-/*
- * Parse arguments. Most of it just gets passed through to the VM. The
- * JNI spec defines a handful of standard arguments.
- */
-int main(int argc, char* const argv[])
-{
- JavaVM* vm = NULL;
- JNIEnv* env = NULL;
- JavaVMInitArgs initArgs;
- JavaVMOption* options = NULL;
- char* slashClass = NULL;
- int optionCount, curOpt, i, argIdx;
- int needExtra = JNI_FALSE;
- int result = 1;
-
- setvbuf(stdout, NULL, _IONBF, 0);
-
- /* ignore argv[0] */
- argv++;
- argc--;
-
- /*
- * If we're adding any additional stuff, e.g. function hook specifiers,
- * add them to the count here.
- *
- * We're over-allocating, because this includes the options to the VM
- * plus the options to the program.
- */
- optionCount = argc;
-
- options = (JavaVMOption*) malloc(sizeof(JavaVMOption) * optionCount);
- memset(options, 0, sizeof(JavaVMOption) * optionCount);
-
- /*
- * Copy options over. Everything up to the name of the class starts
- * with a '-' (the function hook stuff is strictly internal).
- *
- * [Do we need to catch & handle "-jar" here?]
- */
- for (curOpt = argIdx = 0; argIdx < argc; argIdx++) {
- if (argv[argIdx][0] != '-' && !needExtra)
- break;
- options[curOpt++].optionString = strdup(argv[argIdx]);
-
- /* some options require an additional arg */
- needExtra = JNI_FALSE;
- if (strcmp(argv[argIdx], "-classpath") == 0 ||
- strcmp(argv[argIdx], "-cp") == 0)
- /* others? */
- {
- needExtra = JNI_TRUE;
- }
- }
-
- if (needExtra) {
- fprintf(stderr, "Dalvik VM requires value after last option flag\n");
- goto bail;
- }
-
- /* insert additional internal options here */
-
- assert(curOpt <= optionCount);
-
- initArgs.version = JNI_VERSION_1_4;
- initArgs.options = options;
- initArgs.nOptions = curOpt;
- initArgs.ignoreUnrecognized = JNI_FALSE;
-
- //printf("nOptions = %d\n", initArgs.nOptions);
-
- blockSigpipe();
-
- /*
- * Start VM. The current thread becomes the main thread of the VM.
- */
- if (JNI_CreateJavaVM(&vm, &env, &initArgs) < 0) {
- fprintf(stderr, "Dalvik VM init failed (check log file)\n");
- goto bail;
- }
-
- /*
- * Make sure they provided a class name. We do this after VM init
- * so that things like "-Xrunjdwp:help" have the opportunity to emit
- * a usage statement.
- */
- if (argIdx == argc) {
- fprintf(stderr, "Dalvik VM requires a class name\n");
- goto bail;
- }
-
- /*
- * We want to call main() with a String array with our arguments in it.
- * Create an array and populate it. Note argv[0] is not included.
- */
- jobjectArray strArray;
- strArray = createStringArray(env, &argv[argIdx+1], argc-argIdx-1);
- if (strArray == NULL)
- goto bail;
-
- /*
- * Find [class].main(String[]).
- */
- jclass startClass;
- jmethodID startMeth;
- char* cp;
-
- /* convert "com.android.Blah" to "com/android/Blah" */
- slashClass = strdup(argv[argIdx]);
- for (cp = slashClass; *cp != '\0'; cp++)
- if (*cp == '.')
- *cp = '/';
-
- startClass = env->FindClass(slashClass);
- if (startClass == NULL) {
- fprintf(stderr, "Dalvik VM unable to locate class '%s'\n", slashClass);
- goto bail;
- }
-
- startMeth = env->GetStaticMethodID(startClass,
- "main", "([Ljava/lang/String;)V");
- if (startMeth == NULL) {
- fprintf(stderr, "Dalvik VM unable to find static main(String[]) in '%s'\n",
- slashClass);
- goto bail;
- }
-
- /*
- * Make sure the method is public. JNI doesn't prevent us from calling
- * a private method, so we have to check it explicitly.
- */
- if (!methodIsPublic(env, startClass, startMeth))
- goto bail;
-
- /*
- * Invoke main().
- */
- env->CallStaticVoidMethod(startClass, startMeth, strArray);
-
- if (!env->ExceptionCheck())
- result = 0;
-
-bail:
- /*printf("Shutting down Dalvik VM\n");*/
- if (vm != NULL) {
- /*
- * This allows join() and isAlive() on the main thread to work
- * correctly, and also provides uncaught exception handling.
- */
- if (vm->DetachCurrentThread() != JNI_OK) {
- fprintf(stderr, "Warning: unable to detach main thread\n");
- result = 1;
- }
-
- if (vm->DestroyJavaVM() != 0)
- fprintf(stderr, "Warning: Dalvik VM did not shut down cleanly\n");
- /*printf("\nDalvik VM has exited\n");*/
- }
-
- for (i = 0; i < optionCount; i++)
- free((char*) options[i].optionString);
- free(options);
- free(slashClass);
- /*printf("--- VM is down, process exiting\n");*/
- return result;
-}
#LOCAL_CFLAGS += -UNDEBUG -DDEBUG=1
LOCAL_SRC_FILES := $(dex_src_files)
LOCAL_C_INCLUDES += $(dex_include_files)
+LOCAL_STATIC_LIBRARIES := liblog
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := libdex
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(dex_src_files)
LOCAL_C_INCLUDES += $(dex_include_files)
+LOCAL_STATIC_LIBRARIES := liblog
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := libdex
include $(BUILD_HOST_STATIC_LIBRARY)
+++ /dev/null
-# Copyright 2006 The Android Open Source Project
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- Main.cpp \
- Net.cpp \
- find_JdwpConstants.cpp
-
-LOCAL_C_INCLUDES += \
- dalvik/vm
-
-LOCAL_MODULE := jdwpspy
-
-include $(BUILD_HOST_EXECUTABLE)
-
+++ /dev/null
-/*
- * Copyright 2006 The Android Open Source Project
- *
- * jdwpspy common stuff.
- */
-#ifndef _JDWPSPY_COMMON
-#define _JDWPSPY_COMMON
-
-#include <stdio.h>
-#include <sys/types.h>
-
-typedef unsigned char u1;
-typedef unsigned short u2;
-typedef unsigned int u4;
-typedef unsigned long long u8;
-
-#define NELEM(x) (sizeof(x) / sizeof((x)[0]))
-
-#ifndef _JDWP_MISC_INLINE
-# define INLINE extern inline
-#else
-# define INLINE
-#endif
-
-/*
- * Get 1 byte. (Included to make the code more legible.)
- */
-INLINE u1 get1(unsigned const char* pSrc)
-{
- return *pSrc;
-}
-
-/*
- * Get 2 big-endian bytes.
- */
-INLINE u2 get2BE(unsigned char const* pSrc)
-{
- u2 result;
-
- result = *pSrc++ << 8;
- result |= *pSrc++;
-
- return result;
-}
-
-/*
- * Get 4 big-endian bytes.
- */
-INLINE u4 get4BE(unsigned char const* pSrc)
-{
- u4 result;
-
- result = *pSrc++ << 24;
- result |= *pSrc++ << 16;
- result |= *pSrc++ << 8;
- result |= *pSrc++;
-
- return result;
-}
-
-/*
- * Get 8 big-endian bytes.
- */
-INLINE u8 get8BE(unsigned char const* pSrc)
-{
- u8 result;
-
- result = (u8) *pSrc++ << 56;
- result |= (u8) *pSrc++ << 48;
- result |= (u8) *pSrc++ << 40;
- result |= (u8) *pSrc++ << 32;
- result |= (u8) *pSrc++ << 24;
- result |= (u8) *pSrc++ << 16;
- result |= (u8) *pSrc++ << 8;
- result |= (u8) *pSrc++;
-
- return result;
-}
-
-
-/*
- * Start here.
- */
-int run(const char* connectHost, int connectPort, int listenPort);
-
-/*
- * Print a hex dump to the specified file pointer.
- *
- * "local" mode prints a hex dump starting from offset 0 (roughly equivalent
- * to "xxd -g1").
- *
- * "mem" mode shows the actual memory address, and will offset the start
- * so that the low nibble of the address is always zero.
- */
-typedef enum { kHexDumpLocal, kHexDumpMem } HexDumpMode;
-void printHexDump(const void* vaddr, size_t length);
-void printHexDump2(const void* vaddr, size_t length, const char* prefix);
-void printHexDumpEx(FILE* fp, const void* vaddr, size_t length,
- HexDumpMode mode, const char* prefix);
-
-#endif /*_JDWPSPY_COMMON*/
+++ /dev/null
-/*
- * Copyright 2006 The Android Open Source Project
- *
- * JDWP spy.
- */
-#define _JDWP_MISC_INLINE
-#include "Common.h"
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <string.h>
-#include <assert.h>
-#include <ctype.h>
-
-static const char gHexDigit[] = "0123456789abcdef";
-
-/*
- * Print a hex dump. Just hands control off to the fancy version.
- */
-void printHexDump(const void* vaddr, size_t length)
-{
- printHexDumpEx(stdout, vaddr, length, kHexDumpLocal, "");
-}
-void printHexDump2(const void* vaddr, size_t length, const char* prefix)
-{
- printHexDumpEx(stdout, vaddr, length, kHexDumpLocal, prefix);
-}
-
-/*
- * 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
- */
-void printHexDumpEx(FILE* fp, const void* vaddr, size_t length,
- HexDumpMode mode, const char* prefix)
-{
- const unsigned char* addr = reinterpret_cast<const unsigned char*>(vaddr);
- char out[77]; /* exact fit */
- uintptr_t offset; /* offset to show while printing */
- char* hex;
- char* asc;
- int gap;
-
- if (mode == kHexDumpLocal)
- offset = 0;
- else
- offset = (uintptr_t) 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;
- char* hex = out;
- char* asc = out + 59;
-
- for (int i = 0; i < 8; i++) {
- *hex++ = gHexDigit[lineOffset >> 28];
- lineOffset <<= 4;
- }
- hex++;
- hex++;
-
- int 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;
- }
-
- int i;
- for (i = gap ; i < count+gap; i++) {
- *hex++ = gHexDigit[*addr >> 4];
- *hex++ = gHexDigit[*addr & 0x0f];
- hex++;
- if (isprint(*addr))
- *asc++ = *addr;
- else
- *asc++ = '.';
- addr++;
- }
- for ( ; i < 16; i++) {
- /* erase extra stuff; only happens on last line */
- *hex++ = ' ';
- *hex++ = ' ';
- hex++;
- *asc++ = ' ';
- }
-
- fprintf(fp, "%s%s", prefix, out);
-
- gap = 0;
- length -= count;
- offset += count;
- }
-}
-
-
-/*
- * Explain it.
- */
-static void usage(const char* progName)
-{
- fprintf(stderr, "Usage: %s VM-port [debugger-listen-port]\n\n", progName);
- fprintf(stderr,
-"When a debugger connects to the debugger-listen-port, jdwpspy will connect\n");
- fprintf(stderr, "to the VM on the VM-port.\n");
-}
-
-/*
- * Parse args.
- */
-int main(int argc, char* argv[])
-{
- if (argc < 2 || argc > 3) {
- usage("jdwpspy");
- return 2;
- }
-
- setvbuf(stdout, NULL, _IONBF, 0);
-
- /* may want this to be host:port */
- int connectPort = atoi(argv[1]);
-
- int listenPort;
- if (argc > 2)
- listenPort = atoi(argv[2]);
- else
- listenPort = connectPort + 1;
-
- int cc = run("localhost", connectPort, listenPort);
-
- return (cc != 0);
-}
+++ /dev/null
-/*
- * Copyright 2006 The Android Open Source Project
- *
- * JDWP spy. This is a rearranged version of the JDWP code from the VM.
- */
-#include "Common.h"
-#include "jdwp/JdwpConstants.h"
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <time.h>
-#include <errno.h>
-#include <assert.h>
-
-#define kInputBufferSize (256*1024)
-
-#define kMagicHandshakeLen 14 /* "JDWP-Handshake" */
-#define kJDWPHeaderLen 11
-#define kJDWPFlagReply 0x80
-
-
-/*
- * Information about the remote end.
- */
-typedef struct Peer {
- char label[2]; /* 'D' or 'V' */
-
- int sock;
- unsigned char inputBuffer[kInputBufferSize];
- int inputCount;
-
- bool awaitingHandshake; /* waiting for "JDWP-Handshake" */
-} Peer;
-
-
-/*
- * Network state.
- */
-typedef struct NetState {
- /* listen here for connection from debugger */
- int listenSock;
-
- /* connect here to contact VM */
- struct in_addr vmAddr;
- short vmPort;
-
- Peer dbg;
- Peer vm;
-} NetState;
-
-/*
- * Function names.
- */
-typedef struct {
- u1 cmdSet;
- u1 cmd;
- const char* descr;
-} JdwpHandlerMap;
-
-/*
- * Map commands to names.
- *
- * Command sets 0-63 are incoming requests, 64-127 are outbound requests,
- * and 128-256 are vendor-defined.
- */
-static const JdwpHandlerMap gHandlerMap[] = {
- /* VirtualMachine command set (1) */
- { 1, 1, "VirtualMachine.Version" },
- { 1, 2, "VirtualMachine.ClassesBySignature" },
- { 1, 3, "VirtualMachine.AllClasses" },
- { 1, 4, "VirtualMachine.AllThreads" },
- { 1, 5, "VirtualMachine.TopLevelThreadGroups" },
- { 1, 6, "VirtualMachine.Dispose" },
- { 1, 7, "VirtualMachine.IDSizes" },
- { 1, 8, "VirtualMachine.Suspend" },
- { 1, 9, "VirtualMachine.Resume" },
- { 1, 10, "VirtualMachine.Exit" },
- { 1, 11, "VirtualMachine.CreateString" },
- { 1, 12, "VirtualMachine.Capabilities" },
- { 1, 13, "VirtualMachine.ClassPaths" },
- { 1, 14, "VirtualMachine.DisposeObjects" },
- { 1, 15, "VirtualMachine.HoldEvents" },
- { 1, 16, "VirtualMachine.ReleaseEvents" },
- { 1, 17, "VirtualMachine.CapabilitiesNew" },
- { 1, 18, "VirtualMachine.RedefineClasses" },
- { 1, 19, "VirtualMachine.SetDefaultStratum" },
- { 1, 20, "VirtualMachine.AllClassesWithGeneric"},
- { 1, 21, "VirtualMachine.InstanceCounts"},
-
- /* ReferenceType command set (2) */
- { 2, 1, "ReferenceType.Signature" },
- { 2, 2, "ReferenceType.ClassLoader" },
- { 2, 3, "ReferenceType.Modifiers" },
- { 2, 4, "ReferenceType.Fields" },
- { 2, 5, "ReferenceType.Methods" },
- { 2, 6, "ReferenceType.GetValues" },
- { 2, 7, "ReferenceType.SourceFile" },
- { 2, 8, "ReferenceType.NestedTypes" },
- { 2, 9, "ReferenceType.Status" },
- { 2, 10, "ReferenceType.Interfaces" },
- { 2, 11, "ReferenceType.ClassObject" },
- { 2, 12, "ReferenceType.SourceDebugExtension" },
- { 2, 13, "ReferenceType.SignatureWithGeneric" },
- { 2, 14, "ReferenceType.FieldsWithGeneric" },
- { 2, 15, "ReferenceType.MethodsWithGeneric" },
- { 2, 16, "ReferenceType.Instances" },
- { 2, 17, "ReferenceType.ClassFileVersion" },
- { 2, 18, "ReferenceType.ConstantPool" },
-
- /* ClassType command set (3) */
- { 3, 1, "ClassType.Superclass" },
- { 3, 2, "ClassType.SetValues" },
- { 3, 3, "ClassType.InvokeMethod" },
- { 3, 4, "ClassType.NewInstance" },
-
- /* ArrayType command set (4) */
- { 4, 1, "ArrayType.NewInstance" },
-
- /* InterfaceType command set (5) */
-
- /* Method command set (6) */
- { 6, 1, "Method.LineTable" },
- { 6, 2, "Method.VariableTable" },
- { 6, 3, "Method.Bytecodes" },
- { 6, 4, "Method.IsObsolete" },
- { 6, 5, "Method.VariableTableWithGeneric" },
-
- /* Field command set (8) */
-
- /* ObjectReference command set (9) */
- { 9, 1, "ObjectReference.ReferenceType" },
- { 9, 2, "ObjectReference.GetValues" },
- { 9, 3, "ObjectReference.SetValues" },
- { 9, 4, "ObjectReference.UNUSED" },
- { 9, 5, "ObjectReference.MonitorInfo" },
- { 9, 6, "ObjectReference.InvokeMethod" },
- { 9, 7, "ObjectReference.DisableCollection" },
- { 9, 8, "ObjectReference.EnableCollection" },
- { 9, 9, "ObjectReference.IsCollected" },
- { 9, 10, "ObjectReference.ReferringObjects" },
-
- /* StringReference command set (10) */
- { 10, 1, "StringReference.Value" },
-
- /* ThreadReference command set (11) */
- { 11, 1, "ThreadReference.Name" },
- { 11, 2, "ThreadReference.Suspend" },
- { 11, 3, "ThreadReference.Resume" },
- { 11, 4, "ThreadReference.Status" },
- { 11, 5, "ThreadReference.ThreadGroup" },
- { 11, 6, "ThreadReference.Frames" },
- { 11, 7, "ThreadReference.FrameCount" },
- { 11, 8, "ThreadReference.OwnedMonitors" },
- { 11, 9, "ThreadReference.CurrentContendedMonitor" },
- { 11, 10, "ThreadReference.Stop" },
- { 11, 11, "ThreadReference.Interrupt" },
- { 11, 12, "ThreadReference.SuspendCount" },
- { 11, 13, "ThreadReference.OwnedMonitorsStackDepthInfo" },
- { 11, 14, "ThreadReference.ForceEarlyReturn" },
-
- /* ThreadGroupReference command set (12) */
- { 12, 1, "ThreadGroupReference.Name" },
- { 12, 2, "ThreadGroupReference.Parent" },
- { 12, 3, "ThreadGroupReference.Children" },
-
- /* ArrayReference command set (13) */
- { 13, 1, "ArrayReference.Length" },
- { 13, 2, "ArrayReference.GetValues" },
- { 13, 3, "ArrayReference.SetValues" },
-
- /* ClassLoaderReference command set (14) */
- { 14, 1, "ArrayReference.VisibleClasses" },
-
- /* EventRequest command set (15) */
- { 15, 1, "EventRequest.Set" },
- { 15, 2, "EventRequest.Clear" },
- { 15, 3, "EventRequest.ClearAllBreakpoints" },
-
- /* StackFrame command set (16) */
- { 16, 1, "StackFrame.GetValues" },
- { 16, 2, "StackFrame.SetValues" },
- { 16, 3, "StackFrame.ThisObject" },
- { 16, 4, "StackFrame.PopFrames" },
-
- /* ClassObjectReference command set (17) */
- { 17, 1, "ClassObjectReference.ReflectedType" },
-
- /* Event command set (64) */
- { 64, 100, "Event.Composite" },
-
- /* DDMS */
- { 199, 1, "DDMS.Chunk" },
-};
-
-/*
- * Look up a command's name.
- */
-static const char* getCommandName(int cmdSet, int cmd)
-{
- for (int i = 0; i < (int) NELEM(gHandlerMap); i++) {
- if (gHandlerMap[i].cmdSet == cmdSet &&
- gHandlerMap[i].cmd == cmd)
- {
- return gHandlerMap[i].descr;
- }
- }
-
- return "?UNKNOWN?";
-}
-
-
-void jdwpNetFree(NetState* netState); /* fwd */
-
-/*
- * Allocate state structure and bind to the listen port.
- *
- * Returns 0 on success.
- */
-NetState* jdwpNetStartup(unsigned short listenPort, const char* connectHost,
- unsigned short connectPort)
-{
- NetState* netState = (NetState*) malloc(sizeof(*netState));
- memset(netState, 0, sizeof(*netState));
- netState->listenSock = -1;
- netState->dbg.sock = netState->vm.sock = -1;
-
- strcpy(netState->dbg.label, "D");
- strcpy(netState->vm.label, "V");
-
- /*
- * Set up a socket to listen for connections from the debugger.
- */
-
- netState->listenSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (netState->listenSock < 0) {
- fprintf(stderr, "Socket create failed: %s\n", strerror(errno));
- goto fail;
- }
-
- /* allow immediate re-use if we die */
- {
- int one = 1;
- if (setsockopt(netState->listenSock, SOL_SOCKET, SO_REUSEADDR, &one,
- sizeof(one)) < 0)
- {
- fprintf(stderr, "setsockopt(SO_REUSEADDR) failed: %s\n",
- strerror(errno));
- goto fail;
- }
- }
-
- struct sockaddr_in addr;
- addr.sin_family = AF_INET;
- addr.sin_port = htons(listenPort);
- addr.sin_addr.s_addr = INADDR_ANY;
-
- if (bind(netState->listenSock, (struct sockaddr*) &addr, sizeof(addr)) != 0)
- {
- fprintf(stderr, "attempt to bind to port %u failed: %s\n",
- listenPort, strerror(errno));
- goto fail;
- }
-
- fprintf(stderr, "+++ bound to port %u\n", listenPort);
-
- if (listen(netState->listenSock, 5) != 0) {
- fprintf(stderr, "Listen failed: %s\n", strerror(errno));
- goto fail;
- }
-
- /*
- * Do the hostname lookup for the VM.
- */
- struct hostent* pHost;
-
- pHost = gethostbyname(connectHost);
- if (pHost == NULL) {
- fprintf(stderr, "Name lookup of '%s' failed: %s\n",
- connectHost, strerror(h_errno));
- goto fail;
- }
-
- netState->vmAddr = *((struct in_addr*) pHost->h_addr_list[0]);
- netState->vmPort = connectPort;
-
- fprintf(stderr, "+++ connect host resolved to %s\n",
- inet_ntoa(netState->vmAddr));
-
- return netState;
-
-fail:
- jdwpNetFree(netState);
- return NULL;
-}
-
-/*
- * Shut down JDWP listener. Don't free state.
- *
- * Note that "netState" may be partially initialized if "startup" failed.
- */
-void jdwpNetShutdown(NetState* netState)
-{
- int listenSock = netState->listenSock;
- int dbgSock = netState->dbg.sock;
- int vmSock = netState->vm.sock;
-
- /* clear these out so it doesn't wake up and try to reuse them */
- /* (important when multi-threaded) */
- netState->listenSock = netState->dbg.sock = netState->vm.sock = -1;
-
- if (listenSock >= 0) {
- shutdown(listenSock, SHUT_RDWR);
- close(listenSock);
- }
- if (dbgSock >= 0) {
- shutdown(dbgSock, SHUT_RDWR);
- close(dbgSock);
- }
- if (vmSock >= 0) {
- shutdown(vmSock, SHUT_RDWR);
- close(vmSock);
- }
-}
-
-/*
- * Shut down JDWP listener and free its state.
- */
-void jdwpNetFree(NetState* netState)
-{
- if (netState == NULL)
- return;
-
- jdwpNetShutdown(netState);
- free(netState);
-}
-
-/*
- * Disable the TCP Nagle algorithm, which delays transmission of outbound
- * packets until the previous transmissions have been acked. JDWP does a
- * lot of back-and-forth with small packets, so this may help.
- */
-static int setNoDelay(int fd)
-{
- int cc, on = 1;
-
- cc = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
- assert(cc == 0);
- return cc;
-}
-
-/*
- * Accept a connection. This will block waiting for somebody to show up.
- */
-bool jdwpAcceptConnection(NetState* netState)
-{
- struct sockaddr_in addr;
- socklen_t addrlen;
- int sock;
-
- if (netState->listenSock < 0)
- return false; /* you're not listening! */
-
- assert(netState->dbg.sock < 0); /* must not already be talking */
-
- addrlen = sizeof(addr);
- do {
- sock = accept(netState->listenSock, (struct sockaddr*) &addr, &addrlen);
- if (sock < 0 && errno != EINTR) {
- fprintf(stderr, "accept failed: %s\n", strerror(errno));
- return false;
- }
- } while (sock < 0);
-
- fprintf(stderr, "+++ accepted connection from %s:%u\n",
- inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
-
- netState->dbg.sock = sock;
- netState->dbg.awaitingHandshake = true;
- netState->dbg.inputCount = 0;
-
- setNoDelay(sock);
-
- return true;
-}
-
-/*
- * Close the connections to the debugger and VM.
- *
- * Reset the state so we're ready to receive a new connection.
- */
-void jdwpCloseConnection(NetState* netState)
-{
- if (netState->dbg.sock >= 0) {
- fprintf(stderr, "+++ closing connection to debugger\n");
- close(netState->dbg.sock);
- netState->dbg.sock = -1;
- }
- if (netState->vm.sock >= 0) {
- fprintf(stderr, "+++ closing connection to vm\n");
- close(netState->vm.sock);
- netState->vm.sock = -1;
- }
-}
-
-/*
- * Figure out if we have a full packet in the buffer.
- */
-static bool haveFullPacket(Peer* pPeer)
-{
- long length;
-
- if (pPeer->awaitingHandshake)
- return (pPeer->inputCount >= kMagicHandshakeLen);
-
- if (pPeer->inputCount < 4)
- return false;
-
- length = get4BE(pPeer->inputBuffer);
- return (pPeer->inputCount >= length);
-}
-
-/*
- * Consume bytes from the buffer.
- *
- * This would be more efficient with a circular buffer. However, we're
- * usually only going to find one packet, which is trivial to handle.
- */
-static void consumeBytes(Peer* pPeer, int count)
-{
- assert(count > 0);
- assert(count <= pPeer->inputCount);
-
- if (count == pPeer->inputCount) {
- pPeer->inputCount = 0;
- return;
- }
-
- memmove(pPeer->inputBuffer, pPeer->inputBuffer + count,
- pPeer->inputCount - count);
- pPeer->inputCount -= count;
-}
-
-/*
- * Get the current time.
- */
-static void getCurrentTime(int* pMin, int* pSec)
-{
- time_t now;
- struct tm* ptm;
-
- now = time(NULL);
- ptm = localtime(&now);
- *pMin = ptm->tm_min;
- *pSec = ptm->tm_sec;
-}
-
-/*
- * Dump the contents of a packet to stdout.
- */
-static void dumpPacket(const unsigned char* packetBuf, const char* srcName,
- const char* dstName)
-{
- const unsigned char* buf = packetBuf;
- char prefix[3];
- u4 length, id;
- u1 flags, cmdSet=0, cmd=0;
- JdwpError error = ERR_NONE;
- bool reply;
- int dataLen;
-
- length = get4BE(buf+0);
- id = get4BE(buf+4);
- flags = get1(buf+8);
- if ((flags & kJDWPFlagReply) != 0) {
- reply = true;
- error = static_cast<JdwpError>(get2BE(buf+9));
- } else {
- reply = false;
- cmdSet = get1(buf+9);
- cmd = get1(buf+10);
- }
-
- buf += kJDWPHeaderLen;
- dataLen = length - (buf - packetBuf);
-
- if (!reply) {
- prefix[0] = srcName[0];
- prefix[1] = '>';
- } else {
- prefix[0] = dstName[0];
- prefix[1] = '<';
- }
- prefix[2] = '\0';
-
- int min, sec;
- getCurrentTime(&min, &sec);
-
- if (!reply) {
- printf("%s REQUEST dataLen=%-5u id=0x%08x flags=0x%02x cmd=%d/%d [%02d:%02d]\n",
- prefix, dataLen, id, flags, cmdSet, cmd, min, sec);
- printf("%s --> %s\n", prefix, getCommandName(cmdSet, cmd));
- } else {
- printf("%s REPLY dataLen=%-5u id=0x%08x flags=0x%02x err=%d (%s) [%02d:%02d]\n",
- prefix, dataLen, id, flags, error, dvmJdwpErrorStr(error), min,sec);
- }
- if (dataLen > 0)
- printHexDump2(buf, dataLen, prefix);
- printf("%s ----------\n", prefix);
-}
-
-/*
- * Handle a packet. Returns "false" if we encounter a connection-fatal error.
- */
-static bool handlePacket(Peer* pDst, Peer* pSrc)
-{
- const unsigned char* buf = pSrc->inputBuffer;
- u4 length;
- u1 flags;
- int cc;
-
- length = get4BE(buf+0);
- flags = get1(buf+9);
-
- assert((int) length <= pSrc->inputCount);
-
- dumpPacket(buf, pSrc->label, pDst->label);
-
- cc = write(pDst->sock, buf, length);
- if (cc != (int) length) {
- fprintf(stderr, "Failed sending packet: %s\n", strerror(errno));
- return false;
- }
- /*printf("*** wrote %d bytes from %c to %c\n",
- cc, pSrc->label[0], pDst->label[0]);*/
-
- consumeBytes(pSrc, length);
- return true;
-}
-
-/*
- * Handle incoming data. If we have a full packet in the buffer, process it.
- */
-static bool handleIncoming(Peer* pWritePeer, Peer* pReadPeer)
-{
- if (haveFullPacket(pReadPeer)) {
- if (pReadPeer->awaitingHandshake) {
- printf("Handshake [%c]: %.14s\n",
- pReadPeer->label[0], pReadPeer->inputBuffer);
- if (write(pWritePeer->sock, pReadPeer->inputBuffer,
- kMagicHandshakeLen) != kMagicHandshakeLen)
- {
- fprintf(stderr,
- "+++ [%c] handshake write failed\n", pReadPeer->label[0]);
- goto fail;
- }
- consumeBytes(pReadPeer, kMagicHandshakeLen);
- pReadPeer->awaitingHandshake = false;
- } else {
- if (!handlePacket(pWritePeer, pReadPeer))
- goto fail;
- }
- } else {
- /*printf("*** %c not full yet\n", pReadPeer->label[0]);*/
- }
-
- return true;
-
-fail:
- return false;
-}
-
-/*
- * Process incoming data. If no data is available, this will block until
- * some arrives.
- *
- * Returns "false" on error (indicating that the connection has been severed).
- */
-bool jdwpProcessIncoming(NetState* netState)
-{
- int cc;
-
- assert(netState->dbg.sock >= 0);
- assert(netState->vm.sock >= 0);
-
- while (!haveFullPacket(&netState->dbg) && !haveFullPacket(&netState->vm)) {
- /* read some more */
- int highFd;
- fd_set readfds;
-
- highFd = (netState->dbg.sock > netState->vm.sock) ?
- netState->dbg.sock+1 : netState->vm.sock+1;
- FD_ZERO(&readfds);
- FD_SET(netState->dbg.sock, &readfds);
- FD_SET(netState->vm.sock, &readfds);
-
- errno = 0;
- cc = select(highFd, &readfds, NULL, NULL, NULL);
- if (cc < 0) {
- if (errno == EINTR) {
- fprintf(stderr, "+++ EINTR on select\n");
- continue;
- }
- fprintf(stderr, "+++ select failed: %s\n", strerror(errno));
- goto fail;
- }
-
- if (FD_ISSET(netState->dbg.sock, &readfds)) {
- cc = read(netState->dbg.sock,
- netState->dbg.inputBuffer + netState->dbg.inputCount,
- sizeof(netState->dbg.inputBuffer) - netState->dbg.inputCount);
- if (cc < 0) {
- if (errno == EINTR) {
- fprintf(stderr, "+++ EINTR on read\n");
- continue;
- }
- fprintf(stderr, "+++ dbg read failed: %s\n", strerror(errno));
- goto fail;
- }
- if (cc == 0) {
- if (sizeof(netState->dbg.inputBuffer) ==
- netState->dbg.inputCount)
- fprintf(stderr, "+++ debugger sent huge message\n");
- else
- fprintf(stderr, "+++ debugger disconnected\n");
- goto fail;
- }
-
- /*printf("*** %d bytes from dbg\n", cc);*/
- netState->dbg.inputCount += cc;
- }
-
- if (FD_ISSET(netState->vm.sock, &readfds)) {
- cc = read(netState->vm.sock,
- netState->vm.inputBuffer + netState->vm.inputCount,
- sizeof(netState->vm.inputBuffer) - netState->vm.inputCount);
- if (cc < 0) {
- if (errno == EINTR) {
- fprintf(stderr, "+++ EINTR on read\n");
- continue;
- }
- fprintf(stderr, "+++ vm read failed: %s\n", strerror(errno));
- goto fail;
- }
- if (cc == 0) {
- if (sizeof(netState->vm.inputBuffer) ==
- netState->vm.inputCount)
- fprintf(stderr, "+++ vm sent huge message\n");
- else
- fprintf(stderr, "+++ vm disconnected\n");
- goto fail;
- }
-
- /*printf("*** %d bytes from vm\n", cc);*/
- netState->vm.inputCount += cc;
- }
- }
-
- if (!handleIncoming(&netState->dbg, &netState->vm))
- goto fail;
- if (!handleIncoming(&netState->vm, &netState->dbg))
- goto fail;
-
- return true;
-
-fail:
- jdwpCloseConnection(netState);
- return false;
-}
-
-/*
- * Connect to the VM.
- */
-bool jdwpConnectToVm(NetState* netState)
-{
- struct sockaddr_in addr;
- int sock = -1;
-
- sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (sock < 0) {
- fprintf(stderr, "Socket create failed: %s\n", strerror(errno));
- goto fail;
- }
-
- addr.sin_family = AF_INET;
- addr.sin_addr = netState->vmAddr;
- addr.sin_port = htons(netState->vmPort);
- if (connect(sock, (struct sockaddr*) &addr, sizeof(addr)) != 0) {
- fprintf(stderr, "Connection to %s:%u failed: %s\n",
- inet_ntoa(addr.sin_addr), ntohs(addr.sin_port), strerror(errno));
- goto fail;
- }
- fprintf(stderr, "+++ connected to VM %s:%u\n",
- inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
-
- netState->vm.sock = sock;
- netState->vm.awaitingHandshake = true;
- netState->vm.inputCount = 0;
-
- setNoDelay(netState->vm.sock);
- return true;
-
-fail:
- if (sock >= 0)
- close(sock);
- return false;
-}
-
-/*
- * Establish network connections and start things running.
- *
- * We wait for a new connection from the debugger. When one arrives we
- * open a connection to the VM. If one side or the other goes away, we
- * drop both ends and go back to listening.
- */
-int run(const char* connectHost, int connectPort, int listenPort)
-{
- NetState* state;
-
- state = jdwpNetStartup(listenPort, connectHost, connectPort);
- if (state == NULL)
- return -1;
-
- while (true) {
- if (!jdwpAcceptConnection(state))
- break;
-
- if (jdwpConnectToVm(state)) {
- while (true) {
- if (!jdwpProcessIncoming(state))
- break;
- }
- }
-
- jdwpCloseConnection(state);
- }
-
- jdwpNetFree(state);
-
- return 0;
-}
+++ /dev/null
-#include "jdwp/JdwpConstants.cpp"
size_t heapStartingSize;
size_t heapMaximumSize;
size_t heapGrowthLimit;
+ bool lowMemoryMode;
double heapTargetUtilization;
size_t heapMinFree;
size_t heapMaxFree;
ClassObject* classJavaLangReflectMethod;
ClassObject* classJavaLangReflectMethodArray;
ClassObject* classJavaLangReflectProxy;
+ ClassObject* classJavaLangSystem;
ClassObject* classJavaNioDirectByteBuffer;
ClassObject* classLibcoreReflectAnnotationFactory;
ClassObject* classLibcoreReflectAnnotationMember;
/* field offsets - java.lang.reflect.Proxy */
int offJavaLangReflectProxy_h;
+ /* direct method pointer - java.lang.System.runFinalization */
+ Method* methJavaLangSystem_runFinalization;
+
/* field offsets - java.io.FileDescriptor */
int offJavaIoFileDescriptor_descriptor;
#if defined(WITH_JIT)
+#define DEFAULT_CODE_CACHE_SIZE 0xffffffff
+
/* Trace profiling modes. Ordering matters - off states before on states */
enum TraceProfilingModes {
kTraceProfilingDisabled = 0, // Not profiling
/* How many entries in the JitEntryTable are in use */
unsigned int jitTableEntriesUsed;
- /* Bytes allocated for the code cache */
+ /* Max bytes allocated for the code cache. Rough rule of thumb: 1K per 1M of system RAM */
unsigned int codeCacheSize;
/* Trigger for trace selection */
"[,hexopvalue[-endvalue]]*\n");
dvmFprintf(stderr, " -Xincludeselectedmethod\n");
dvmFprintf(stderr, " -Xjitthreshold:decimalvalue\n");
+ dvmFprintf(stderr, " -Xjitcodecachesize:decimalvalueofkbytes\n");
dvmFprintf(stderr, " -Xjitblocking\n");
dvmFprintf(stderr, " -Xjitmethod:signature[,signature]* "
"(eg Ljava/lang/String\\;replace)\n");
dvmFprintf(stderr, "Invalid -XX:HeapMaxFree option '%s'\n", argv[i]);
return -1;
}
+ } else if (strcmp(argv[i], "-XX:LowMemoryMode") == 0) {
+ gDvm.lowMemoryMode = true;
} else if (strncmp(argv[i], "-XX:HeapTargetUtilization=", 26) == 0) {
const char* start = argv[i] + 26;
const char* end = start;
gDvmJit.blockingMode = true;
} else if (strncmp(argv[i], "-Xjitthreshold:", 15) == 0) {
gDvmJit.threshold = atoi(argv[i] + 15);
+ } else if (strncmp(argv[i], "-Xjitcodecachesize:", 19) == 0) {
+ gDvmJit.codeCacheSize = atoi(argv[i] + 19) * 1024;
+ if (gDvmJit.codeCacheSize == 0) {
+ gDvm.executionMode = kExecutionModeInterpFast;
+ }
} else if (strncmp(argv[i], "-Xincludeselectedop", 19) == 0) {
gDvmJit.includeSelectedOp = true;
} else if (strncmp(argv[i], "-Xincludeselectedmethod", 23) == 0) {
gDvm.heapStartingSize = 2 * 1024 * 1024; // Spec says 16MB; too big for us.
gDvm.heapMaximumSize = 16 * 1024 * 1024; // Spec says 75% physical mem
gDvm.heapGrowthLimit = 0; // 0 means no growth limit
+ gDvm.lowMemoryMode = false;
gDvm.stackSize = kDefaultStackSize;
gDvm.mainThreadStackSize = kDefaultStackSize;
// When the heap is less than the maximum or growth limited size,
gDvmJit.includeSelectedOffset = false;
gDvmJit.methodTable = NULL;
gDvmJit.classTable = NULL;
+ gDvmJit.codeCacheSize = DEFAULT_CODE_CACHE_SIZE;
gDvm.constInit = false;
gDvm.commonInit = false;
#ifdef HAVE_ANDROID_OS
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) {
- if (errno == EINVAL) {
- SLOGW("PR_SET_NO_NEW_PRIVS failed. "
- "Is your kernel compiled correctly?: %s", strerror(errno));
- // Don't return -1 here, since it's expected that not all
- // kernels will support this option.
- } else {
- SLOGW("PR_SET_NO_NEW_PRIVS failed: %s", strerror(errno));
+ // Older kernels don't understand PR_SET_NO_NEW_PRIVS and return
+ // EINVAL. Don't die on such kernels.
+ if (errno != EINVAL) {
+ SLOGE("PR_SET_NO_NEW_PRIVS failed: %s", strerror(errno));
return -1;
}
}
{ &gDvm.classJavaLangReflectMethod, "Ljava/lang/reflect/Method;" },
{ &gDvm.classJavaLangReflectMethodArray, "[Ljava/lang/reflect/Method;"},
{ &gDvm.classJavaLangReflectProxy, "Ljava/lang/reflect/Proxy;" },
+ { &gDvm.classJavaLangSystem, "Ljava/lang/System;" },
{ &gDvm.classJavaNioDirectByteBuffer, "Ljava/nio/DirectByteBuffer;" },
{ &gDvm.classOrgApacheHarmonyDalvikDdmcChunk, "Lorg/apache/harmony/dalvik/ddmc/Chunk;" },
{ &gDvm.classOrgApacheHarmonyDalvikDdmcDdmServer,
"getSystemClassLoader", "()Ljava/lang/ClassLoader;" },
{ &gDvm.methJavaLangReflectProxy_constructorPrototype, "Ljava/lang/reflect/Proxy;",
"constructorPrototype", "(Ljava/lang/reflect/InvocationHandler;)V" },
+ { &gDvm.methJavaLangSystem_runFinalization, "Ljava/lang/System;",
+ "runFinalization", "()V" },
+
{ &gDvm.methodTraceGcMethod, "Ldalvik/system/VMDebug;", "startGC", "()V" },
{ &gDvm.methodTraceClassPrepMethod, "Ldalvik/system/VMDebug;", "startClassPrep", "()V" },
{ &gDvm.methOrgApacheHarmonyLangAnnotationAnnotationFactory_createAnnotation,
* Garbage-collecting memory allocator.
*/
#include "Dalvik.h"
+#include "Globals.h"
#include "alloc/Heap.h"
#include "alloc/HeapInternal.h"
#include "alloc/HeapSource.h"
+#include "cutils/atomic.h"
+#include "cutils/atomic-inline.h"
/*
* Initialize the GC universe.
dvmUnlockHeap();
}
+/*
+ * Run finalization.
+ */
+void dvmRunFinalization() {
+ Thread *self = dvmThreadSelf();
+ assert(self != NULL);
+ JValue unusedResult;
+ dvmCallMethod(self, gDvm.methJavaLangSystem_runFinalization, NULL, &unusedResult);
+}
+
struct CountContext {
const ClassObject *clazz;
size_t count;
void dvmCollectGarbage(void);
/*
+ * Calls System.runFinalization().
+ */
+void dvmRunFinalization();
+
+/*
* Returns a count of the direct instances of a class.
*/
size_t dvmCountInstancesOfClass(const ClassObject *clazz);
*/
assert(gDvm.gcHeap->cardTableBase != NULL);
-#if 1
- // zero out cards with memset(), using liveBits as an estimate
- const HeapBitmap* liveBits = dvmHeapSourceGetLiveBits();
- size_t maxLiveCard = (liveBits->max - liveBits->base) / GC_CARD_SIZE;
- maxLiveCard = ALIGN_UP_TO_PAGE_SIZE(maxLiveCard);
- if (maxLiveCard > gDvm.gcHeap->cardTableLength) {
- maxLiveCard = gDvm.gcHeap->cardTableLength;
- }
+ if (gDvm.lowMemoryMode) {
+ // zero out cards with madvise(), discarding all pages in the card table
+ madvise(gDvm.gcHeap->cardTableBase, gDvm.gcHeap->cardTableLength, MADV_DONTNEED);
+ } else {
+ // zero out cards with memset(), using liveBits as an estimate
+ const HeapBitmap* liveBits = dvmHeapSourceGetLiveBits();
+ size_t maxLiveCard = (liveBits->max - liveBits->base) / GC_CARD_SIZE;
+ maxLiveCard = ALIGN_UP_TO_PAGE_SIZE(maxLiveCard);
+ if (maxLiveCard > gDvm.gcHeap->cardTableLength) {
+ maxLiveCard = gDvm.gcHeap->cardTableLength;
+ }
- memset(gDvm.gcHeap->cardTableBase, GC_CARD_CLEAN, maxLiveCard);
-#else
- // zero out cards with madvise(), discarding all pages in the card table
- madvise(gDvm.gcHeap->cardTableBase, gDvm.gcHeap->cardTableLength,
- MADV_DONTNEED);
-#endif
+ memset(gDvm.gcHeap->cardTableBase, GC_CARD_CLEAN, maxLiveCard);
+ }
}
/*
#include "alloc/MarkSweep.h"
#include "os/os.h"
-#include <sys/time.h>
+#include <sys/mman.h>
#include <sys/resource.h>
+#include <sys/time.h>
#include <limits.h>
#include <errno.h>
HeapBitmap markBits;
/*
+ * Native allocations.
+ */
+ int32_t nativeBytesAllocated;
+ size_t nativeFootprintGCWatermark;
+ size_t nativeFootprintLimit;
+
+ /*
* State for the GC daemon.
*/
bool hasGcThread;
hs->softLimit = SIZE_MAX; // no soft limit at first
hs->numHeaps = 0;
hs->sawZygote = gDvm.zygote;
+ hs->nativeBytesAllocated = 0;
+ hs->nativeFootprintGCWatermark = startSize;
+ hs->nativeFootprintLimit = startSize * 2;
hs->hasGcThread = false;
hs->heapBase = (char *)base;
hs->heapLength = length;
FRACTIONAL_MB(hs->softLimit), n);
return NULL;
}
- void* ptr = mspace_calloc(heap->msp, 1, n);
- if (ptr == NULL) {
- return NULL;
+ void* ptr;
+ if (gDvm.lowMemoryMode) {
+ /* This is only necessary because mspace_calloc always memsets the
+ * allocated memory to 0. This is bad for memory usage since it leads
+ * to dirty zero pages. If low memory mode is enabled, we use
+ * mspace_malloc which doesn't memset the allocated memory and madvise
+ * the page aligned region back to the kernel.
+ */
+ ptr = mspace_malloc(heap->msp, n);
+ if (ptr == NULL) {
+ return NULL;
+ }
+ uintptr_t zero_begin = (uintptr_t)ptr;
+ uintptr_t zero_end = (uintptr_t)ptr + n;
+ /* Calculate the page aligned region.
+ */
+ uintptr_t begin = ALIGN_UP_TO_PAGE_SIZE(zero_begin);
+ uintptr_t end = zero_end & ~(uintptr_t)(SYSTEM_PAGE_SIZE - 1);
+ /* If our allocation spans more than one page, we attempt to madvise.
+ */
+ if (begin < end) {
+ /* madvise the page aligned region to kernel.
+ */
+ madvise((void*)begin, end - begin, MADV_DONTNEED);
+ /* Zero the region after the page aligned region.
+ */
+ memset((void*)end, 0, zero_end - end);
+ /* Zero out the region before the page aligned region.
+ */
+ zero_end = begin;
+ }
+ memset((void*)zero_begin, 0, zero_end - zero_begin);
+ } else {
+ ptr = mspace_calloc(heap->msp, 1, n);
+ if (ptr == NULL) {
+ return NULL;
+ }
}
+
countAllocation(heap, ptr);
/*
* Check to see if a concurrent GC should be initiated.
return NULL;
}
}
+
+static void dvmHeapSourceUpdateMaxNativeFootprint()
+{
+ /* Use the current target utilization ratio to determine the new native GC
+ * watermarks.
+ */
+ size_t nativeSize = gHs->nativeBytesAllocated;
+ size_t targetSize =
+ (nativeSize / gHs->targetUtilization) * HEAP_UTILIZATION_MAX;
+
+ if (targetSize > nativeSize + gHs->maxFree) {
+ targetSize = nativeSize + gHs->maxFree;
+ } else if (targetSize < nativeSize + gHs->minFree) {
+ targetSize = nativeSize + gHs->minFree;
+ }
+ gHs->nativeFootprintGCWatermark = targetSize;
+ gHs->nativeFootprintLimit = 2 * targetSize - nativeSize;
+}
+
+void dvmHeapSourceRegisterNativeAllocation(int bytes)
+{
+ android_atomic_add(bytes, &gHs->nativeBytesAllocated);
+
+ if ((size_t)gHs->nativeBytesAllocated > gHs->nativeFootprintGCWatermark) {
+ /* The second watermark is higher than the gc watermark. If you hit
+ * this it means you are allocating native objects faster than the GC
+ * can keep up with. If this occurs, we do a GC for alloc.
+ */
+ if ((size_t)gHs->nativeBytesAllocated > gHs->nativeFootprintLimit) {
+ Thread* self = dvmThreadSelf();
+
+ dvmRunFinalization();
+ if (!dvmCheckException(self)) {
+ return;
+ }
+
+ dvmLockHeap();
+ bool waited = dvmWaitForConcurrentGcToComplete();
+ dvmUnlockHeap();
+ if (waited) {
+ // Just finished a GC, attempt to run finalizers.
+ dvmRunFinalization();
+ if (!dvmCheckException(self)) {
+ return;
+ }
+ }
+
+ // If we still are over the watermark, attempt a GC for alloc and run finalizers.
+ if ((size_t)gHs->nativeBytesAllocated > gHs->nativeFootprintLimit) {
+ dvmLockHeap();
+ dvmWaitForConcurrentGcToComplete();
+ dvmCollectGarbageInternal(GC_FOR_MALLOC);
+ dvmUnlockHeap();
+ dvmRunFinalization();
+
+ if (!dvmCheckException(self)) {
+ return;
+ }
+ }
+ /* We have just run finalizers, update the native watermark since
+ * it is very likely that finalizers released native managed
+ * allocations.
+ */
+ dvmHeapSourceUpdateMaxNativeFootprint();
+ } else {
+ dvmSignalCond(&gHs->gcThreadCond);
+ }
+ }
+}
+
+/*
+ * Called from VMRuntime.registerNativeFree.
+ */
+void dvmHeapSourceRegisterNativeFree(int bytes)
+{
+ int expected_size, new_size;
+ do {
+ expected_size = gHs->nativeBytesAllocated;
+ new_size = expected_size - bytes;
+ if (new_size < 0) {
+ break;
+ }
+ } while (android_atomic_cas(expected_size, new_size,
+ &gHs->nativeBytesAllocated));
+}
*/
size_t dvmHeapSourceGetMaximumSize(void);
+/*
+ * Called from VMRuntime.registerNativeAllocation.
+ */
+void dvmHeapSourceRegisterNativeAllocation(int bytes);
+
+/*
+ * Called from VMRuntime.registerNativeFree.
+ */
+void dvmHeapSourceRegisterNativeFree(int bytes);
+
#endif // DALVIK_HEAP_SOURCE_H_
MAP_PRIVATE , fd, 0);
close(fd);
if (gDvmJit.codeCache == MAP_FAILED) {
- ALOGE("Failed to mmap the JIT code cache: %s", strerror(errno));
+ ALOGE("Failed to mmap the JIT code cache of size %d: %s", gDvmJit.codeCacheSize, strerror(errno));
return false;
}
}
ALOGD("JIT: Average execution count -> %d",(int)(sum / numTraces));
+ // How efficiently are we using code cache memory? Bigger is better.
+ ALOGD("JIT: CodeCache efficiency -> %.2f",(float)sum / (float)gDvmJit.codeCacheByteUsed);
/* Dump the sorted entries. The count of each trace will be reset to 0. */
for (i=0; i < gDvmJit.jitTableSize; i++) {
if (gDvmJit.threshold == 0) {
gDvmJit.threshold = 200;
}
- gDvmJit.codeCacheSize = 512*1024;
+ if (gDvmJit.codeCacheSize == DEFAULT_CODE_CACHE_SIZE) {
+ gDvmJit.codeCacheSize = 512 * 1024;
+ } else if ((gDvmJit.codeCacheSize == 0) && (gDvm.executionMode == kExecutionModeJit)) {
+ gDvm.executionMode = kExecutionModeInterpFast;
+ }
+ /* Hard limit for Arm of 2M */
+ assert(gDvmJit.codeCacheSize <= 2 * 1024 * 1024);
#if defined(WITH_SELF_VERIFICATION)
/* Force into blocking mode */
if (gDvmJit.threshold == 0) {
gDvmJit.threshold = 200;
}
- gDvmJit.codeCacheSize = 512*1024;
+ if (gDvmJit.codeCacheSize == DEFAULT_CODE_CACHE_SIZE) {
+ gDvmJit.codeCacheSize = 512 * 1024;
+ } else if ((gDvmJit.codeCacheSize == 0) && (gDvm.executionMode == kExecutionModeJit)) {
+ gDvm.executionMode = kExecutionModeInterpFast;
+ }
+ /* Hard limit for Arm of 2M */
+ assert(gDvmJit.codeCacheSize <= 2 * 1024 * 1024);
#if defined(WITH_SELF_VERIFICATION)
/* Force into blocking mode */
if (gDvmJit.threshold == 0) {
gDvmJit.threshold = 40;
}
- gDvmJit.codeCacheSize = 1024*1024;
+ if (gDvmJit.codeCacheSize == DEFAULT_CODE_CACHE_SIZE) {
+ gDvmJit.codeCacheSize = 1500 * 1024;
+ } else if ((gDvmJit.codeCacheSize == 0) && (gDvm.executionMode == kExecutionModeJit)) {
+ gDvm.executionMode = kExecutionModeInterpFast;
+ }
+ /* Hard limit for Arm of 2M */
+ assert(gDvmJit.codeCacheSize <= 2 * 1024 * 1024);
#if defined(WITH_SELF_VERIFICATION)
/* Force into blocking */
if (gDvmJit.threshold == 0) {
gDvmJit.threshold = 40;
}
- gDvmJit.codeCacheSize = 1024*1024;
+ if (gDvmJit.codeCacheSize == DEFAULT_CODE_CACHE_SIZE) {
+ gDvmJit.codeCacheSize = 1500 * 1024;
+ } else if ((gDvmJit.codeCacheSize == 0) && (gDvm.executionMode == kExecutionModeJit)) {
+ gDvm.executionMode = kExecutionModeInterpFast;
+ }
+ /* Hard limit for Arm of 2M */
+ assert(gDvmJit.codeCacheSize <= 2 * 1024 * 1024);
#if defined(WITH_SELF_VERIFICATION)
/* Force into blocking */
if (gDvmJit.threshold == 0) {
gDvmJit.threshold = 200;
}
- gDvmJit.codeCacheSize = 512*1024;
+ if (gDvmJit.codeCacheSize == DEFAULT_CODE_CACHE_SIZE) {
+ gDvmJit.codeCacheSize = 512 * 1024;
+ } else if ((gDvmJit.codeCacheSize == 0) && (gDvm.executionMode == kExecutionModeJit)) {
+ gDvm.executionMode = kExecutionModeInterpFast;
+ }
#if defined(WITH_SELF_VERIFICATION)
/* Force into blocking mode */
if (gDvmJit.threshold == 0) {
gDvmJit.threshold = 255;
}
- gDvmJit.codeCacheSize = 512*1024;
+ if (gDvmJit.codeCacheSize == DEFAULT_CODE_CACHE_SIZE) {
+ gDvmJit.codeCacheSize = 512 * 1024;
+ } else if ((gDvmJit.codeCacheSize == 0) && (gDvm.executionMode == kExecutionModeJit)) {
+ gDvm.executionMode = kExecutionModeInterpFast;
+ }
gDvmJit.optLevel = kJitOptLevelO1;
//Disable Method-JIT
#include "enc_base.h"
#include "enc_wrapper.h"
#include "dec_base.h"
-#include "utils/Log.h"
+#include <cutils/log.h>
//#define PRINT_ENCODER_STREAM
bool dump_x86_inst = false;
/* Number of entries in the 2nd level JIT profiler filter cache */
#define JIT_TRACE_THRESH_FILTER_SIZE 32
/* Number of low dalvik pc address bits to include in 2nd level filter key */
-#define JIT_TRACE_THRESH_FILTER_PC_BITS 4
+#define JIT_TRACE_THRESH_FILTER_PC_BITS 16
#define MAX_JIT_RUN_LEN 64
enum JitHint {
* dalvik.system.VMRuntime
*/
#include "Dalvik.h"
+#include "alloc/HeapSource.h"
#include "ScopedPthreadMutexLock.h"
#include "native/InternalNativePriv.h"
returnCString(pResult, buf);
}
+static void Dalvik_dalvik_system_VMRuntime_vmLibrary(const u4* args,
+ JValue* pResult)
+{
+ returnCString(pResult, "libdvm.so");
+}
+
static void Dalvik_dalvik_system_VMRuntime_setTargetSdkVersion(const u4* args,
JValue* pResult)
{
RETURN_VOID();
}
+static void Dalvik_dalvik_system_VMRuntime_registerNativeAllocation(const u4* args,
+ JValue* pResult)
+{
+ int bytes = args[1];
+ if (bytes < 0) {
+ dvmThrowRuntimeException("allocation size negative");
+ } else {
+ dvmHeapSourceRegisterNativeAllocation(bytes);
+ }
+ RETURN_VOID();
+}
+
+static void Dalvik_dalvik_system_VMRuntime_registerNativeFree(const u4* args,
+ JValue* pResult)
+{
+ int bytes = args[1];
+ if (bytes < 0) {
+ dvmThrowRuntimeException("allocation size negative");
+ } else {
+ dvmHeapSourceRegisterNativeFree(bytes);
+ }
+ RETURN_VOID();
+}
+
+static void Dalvik_dalvik_system_VMRuntime_updateProcessState(const u4* args,
+ JValue* pResult) {
+ // updateProcessState is used in ART to help determine GC behavior. Currently
+ // in Dalvik we don't use process states for anything.
+ RETURN_VOID();
+}
+
const DalvikNativeMethod dvm_dalvik_system_VMRuntime[] = {
{ "addressOf", "(Ljava/lang/Object;)J",
Dalvik_dalvik_system_VMRuntime_addressOf },
Dalvik_dalvik_system_VMRuntime_startJitCompilation },
{ "vmVersion", "()Ljava/lang/String;",
Dalvik_dalvik_system_VMRuntime_vmVersion },
+ { "vmLibrary", "()Ljava/lang/String;",
+ Dalvik_dalvik_system_VMRuntime_vmLibrary },
+ { "registerNativeAllocation", "(I)V",
+ Dalvik_dalvik_system_VMRuntime_registerNativeAllocation },
+ { "registerNativeFree", "(I)V",
+ Dalvik_dalvik_system_VMRuntime_registerNativeFree },
+ { "updateProcessState", "(I)V",
+ Dalvik_dalvik_system_VMRuntime_updateProcessState },
{ NULL, NULL, NULL },
};
#include <limits.h>
#include <errno.h>
+#include <system/thread_defs.h>
#include <cutils/sched_policy.h>
-#include <utils/threads.h>
/*
* Conversion map for "nice" values.