/*
* 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.
*/
/*
* Variables with library scope.
*
* Prefer this over scattered static and global variables -- it's easier to
* view the state in a debugger, it makes clean shutdown simpler, we can
* trivially dump the state into a crash log, and it dodges most naming
* collisions that will arise when we are embedded in a larger program.
*
* If we want multiple VMs per process, this can get stuffed into TLS (or
* accessed through a Thread field). May need to pass it around for some
* of the early initialization functions.
*/
#ifndef _DALVIK_GLOBALS
#define _DALVIK_GLOBALS
#include <stdarg.h>
#include <pthread.h>
#define MAX_BREAKPOINTS 20 /* used for a debugger optimization */
/* private structures */
typedef struct GcHeap GcHeap;
typedef struct BreakpointSet BreakpointSet;
/*
* One of these for each -ea/-da/-esa/-dsa on the command line.
*/
typedef struct AssertionControl {
char* pkgOrClass; /* package/class string, or NULL for esa/dsa */
int pkgOrClassLen; /* string length, for quick compare */
bool enable; /* enable or disable */
bool isPackage; /* string ended with "..."? */
} AssertionControl;
/*
* Execution mode, e.g. interpreter vs. JIT.
*/
typedef enum ExecutionMode {
kExecutionModeUnknown = 0,
kExecutionModeInterpPortable,
kExecutionModeInterpFast,
#if defined(WITH_JIT)
kExecutionModeJit,
#endif
} ExecutionMode;
/*
* All fields are initialized to zero.
*
* Storage allocated here must be freed by a subsystem shutdown function or
* from within freeGlobals().
*/
struct DvmGlobals {
/*
* Some options from the command line or environment.
*/
char* bootClassPathStr;
char* classPathStr;
unsigned int heapSizeStart;
unsigned int heapSizeMax;
unsigned int stackSize;
bool verboseGc;
bool verboseJni;
bool verboseClass;
bool verboseShutdown;
bool jdwpAllowed; // debugging allowed for this process?
bool jdwpConfigured; // has debugging info been provided?
int jdwpTransport;
bool jdwpServer;
char* jdwpHost;
int jdwpPort;
bool jdwpSuspend;
/*
* Lock profiling threshold value in milliseconds. Acquires that
* exceed threshold are logged. Acquires within the threshold are
* logged with a probability of $\frac{time}{threshold}$ . If the
* threshold is unset no additional logging occurs.
*/
u4 lockProfThreshold;
int (*vfprintfHook)(FILE*, const char*, va_list);
void (*exitHook)(int);
void (*abortHook)(void);
int jniGrefLimit; // 0 means no limit
bool reduceSignals;
bool noQuitHandler;
bool verifyDexChecksum;
char* stackTraceFile; // for SIGQUIT-inspired output
bool logStdio;
DexOptimizerMode dexOptMode;
DexClassVerifyMode classVerifyMode;
bool preciseGc;
bool generateRegisterMaps;
int assertionCtrlCount;
AssertionControl* assertionCtrl;
ExecutionMode executionMode;
/*
* VM init management.
*/
bool initializing;
int initExceptionCount;
bool optimizing;
/*
* java.lang.System properties set from the command line.
*/
int numProps;
int maxProps;
char** propList;
/*
* Where the VM goes to find system classes.
*/
ClassPathEntry* bootClassPath;
/* used by the DEX optimizer to load classes from an unfinished DEX */
DvmDex* bootClassPathOptExtra;
bool optimizingBootstrapClass;
/*
* Loaded classes, hashed by class name. Each entry is a ClassObject*,
* allocated in GC space.
*/
HashTable* loadedClasses;
/*
* Value for the next class serial number to be assigned. This is
* incremented as we load classes. Failed loads and races may result
* in some numbers being skipped, and the serial number is not
* guaranteed to start at 1, so the current value should not be used
* as a count of loaded classes.
*/
volatile int classSerialNumber;
/*
* Classes with a low classSerialNumber are probably in the zygote, and
* their InitiatingLoaderList is not used, to promote sharing. The list is
* kept here instead.
*/
InitiatingLoaderList* initiatingLoaderList;
/*
* Interned strings.
*/
HashTable* internedStrings;
/*
* Quick lookups for popular classes used internally.
*/
ClassObject* unlinkedJavaLangClass; // see unlinkedJavaLangClassObject
ClassObject* classJavaLangClass;
ClassObject* classJavaLangClassArray;
ClassObject* classJavaLangError;
ClassObject* classJavaLangObject;
ClassObject* classJavaLangObjectArray;
ClassObject* classJavaLangRuntimeException;
ClassObject* classJavaLangString;
ClassObject* classJavaLangThread;
ClassObject* classJavaLangVMThread;
ClassObject* classJavaLangThreadGroup;
ClassObject* classJavaLangThrowable;
ClassObject* classJavaLangStackOverflowError;
ClassObject* classJavaLangStackTraceElement;
ClassObject* classJavaLangStackTraceElementArray;
ClassObject* classJavaLangAnnotationAnnotationArray;
ClassObject* classJavaLangAnnotationAnnotationArrayArray;
ClassObject* classJavaLangReflectAccessibleObject;
ClassObject* classJavaLangReflectConstructor;
ClassObject* classJavaLangReflectConstructorArray;
ClassObject* classJavaLangReflectField;
ClassObject* classJavaLangReflectFieldArray;
ClassObject* classJavaLangReflectMethod;
ClassObject* classJavaLangReflectMethodArray;
ClassObject* classJavaLangReflectProxy;
ClassObject* classJavaLangExceptionInInitializerError;
ClassObject* classJavaLangRefPhantomReference;
ClassObject* classJavaLangRefReference;
ClassObject* classJavaNioReadWriteDirectByteBuffer;
ClassObject* classJavaSecurityAccessController;
ClassObject* classOrgApacheHarmonyLangAnnotationAnnotationFactory;
ClassObject* classOrgApacheHarmonyLangAnnotationAnnotationMember;
ClassObject* classOrgApacheHarmonyLangAnnotationAnnotationMemberArray;
ClassObject* classOrgApacheHarmonyNioInternalDirectBuffer;
jclass jclassOrgApacheHarmonyNioInternalDirectBuffer;
/* synthetic classes for arrays of primitives */
ClassObject* classArrayBoolean;
ClassObject* classArrayChar;
ClassObject* classArrayFloat;
ClassObject* classArrayDouble;
ClassObject* classArrayByte;
ClassObject* classArrayShort;
ClassObject* classArrayInt;
ClassObject* classArrayLong;
/* method offsets - Object */
int voffJavaLangObject_equals;
int voffJavaLangObject_hashCode;
int voffJavaLangObject_toString;
int voffJavaLangObject_finalize;
/* field offsets - Class */
int offJavaLangClass_pd;
/* field offsets - String */
volatile int javaLangStringReady; /* 0=not init, 1=ready, -1=initing */
int offJavaLangString_value;
int offJavaLangString_count;
int offJavaLangString_offset;
int offJavaLangString_hashCode;
/* field offsets - Thread */
int offJavaLangThread_vmThread;
int offJavaLangThread_group;
int offJavaLangThread_daemon;
int offJavaLangThread_name;
int offJavaLangThread_priority;
/* method offsets - Thread */
int voffJavaLangThread_run;
/* field offsets - VMThread */
int offJavaLangVMThread_thread;
int offJavaLangVMThread_vmData;
/* method offsets - ThreadGroup */
int voffJavaLangThreadGroup_removeThread;
/* field offsets - Throwable */
int offJavaLangThrowable_stackState;
int offJavaLangThrowable_message;
int offJavaLangThrowable_cause;
/* field offsets - java.lang.reflect.* */
int offJavaLangReflectAccessibleObject_flag;
int offJavaLangReflectConstructor_slot;
int offJavaLangReflectConstructor_declClass;
int offJavaLangReflectField_slot;
int offJavaLangReflectField_declClass;
int offJavaLangReflectMethod_slot;
int offJavaLangReflectMethod_declClass;
/* field offsets - java.lang.ref.Reference */
int offJavaLangRefReference_referent;
int offJavaLangRefReference_queue;
int offJavaLangRefReference_queueNext;
int offJavaLangRefReference_vmData;
/* method pointers - java.lang.ref.Reference */
Method* methJavaLangRefReference_enqueueInternal;
/* field offsets - java.nio.Buffer and java.nio.DirectByteBufferImpl */
//int offJavaNioBuffer_capacity;
//int offJavaNioDirectByteBufferImpl_pointer;
/* method pointers - java.security.AccessController */
volatile bool javaSecurityAccessControllerReady;
Method* methJavaSecurityAccessController_doPrivileged[4];
/* constructor method pointers; no vtable involved, so use Method* */
Method* methJavaLangStackTraceElement_init;
Method* methJavaLangExceptionInInitializerError_init;
Method* methJavaLangRefPhantomReference_init;
Method* methJavaLangReflectConstructor_init;
Method* methJavaLangReflectField_init;
Method* methJavaLangReflectMethod_init;
Method* methOrgApacheHarmonyLangAnnotationAnnotationMember_init;
/* static method pointers - android.lang.annotation.* */
Method*
methOrgApacheHarmonyLangAnnotationAnnotationFactory_createAnnotation;
/* direct method pointers - java.lang.reflect.Proxy */
Method* methJavaLangReflectProxy_constructorPrototype;
/* field offsets - java.lang.reflect.Proxy */
int offJavaLangReflectProxy_h;
/* fake native entry point method */
Method* methFakeNativeEntry;
/* assorted direct buffer helpers */
Method* methJavaNioReadWriteDirectByteBuffer_init;
Method* methOrgApacheHarmonyLuniPlatformPlatformAddress_on;
Method* methOrgApacheHarmonyNioInternalDirectBuffer_getEffectiveAddress;
int offJavaNioBuffer_capacity;
int offJavaNioBuffer_effectiveDirectAddress;
int offOrgApacheHarmonyLuniPlatformPlatformAddress_osaddr;
int voffOrgApacheHarmonyLuniPlatformPlatformAddress_toLong;
/*
* VM-synthesized primitive classes, for arrays.
*/
ClassObject* volatile primitiveClass[PRIM_MAX];
/*
* A placeholder ClassObject used during ClassObject
* construction.
*/
ClassObject unlinkedJavaLangClassObject;
/*
* Thread list. This always has at least one element in it (main),
* and main is always the first entry.
*
* The threadListLock is used for several things, including the thread
* start condition variable. Generally speaking, you must hold the
* threadListLock when:
* - adding/removing items from the list
* - waiting on or signaling threadStartCond
* - examining the Thread struct for another thread (this is to avoid
* one thread freeing the Thread struct while another thread is
* perusing it)
*/
Thread* threadList;
pthread_mutex_t threadListLock;
pthread_cond_t threadStartCond;
/*
* The thread code grabs this before suspending all threads. There
* are a few things that can cause a "suspend all":
* (1) the GC is starting;
* (2) the debugger has sent a "suspend all" request;
* (3) a thread has hit a breakpoint or exception that the debugger
* has marked as a "suspend all" event;
* (4) the SignalCatcher caught a signal that requires suspension.
* (5) (if implemented) the JIT needs to perform a heavyweight
* rearrangement of the translation cache or JitTable.
*
* Because we use "safe point" self-suspension, it is never safe to
* do a blocking "lock" call on this mutex -- if it has been acquired,
* somebody is probably trying to put you to sleep. The leading '_' is
* intended as a reminder that this lock is special.
*/
pthread_mutex_t _threadSuspendLock;
/*
* Guards Thread->suspendCount for all threads, and provides the lock
* for the condition variable that all suspended threads sleep on
* (threadSuspendCountCond).
*
* This has to be separate from threadListLock because of the way
* threads put themselves to sleep.
*/
pthread_mutex_t threadSuspendCountLock;
/*
* Suspended threads sleep on this. They should sleep on the condition
* variable until their "suspend count" is zero.
*
* Paired with "threadSuspendCountLock".
*/
pthread_cond_t threadSuspendCountCond;
/*
* Sum of all threads' suspendCount fields. The JIT needs to know if any
* thread is suspended. Guarded by threadSuspendCountLock.
*/
int sumThreadSuspendCount;
/*
* MUTEX ORDERING: when locking multiple mutexes, always grab them in
* this order to avoid deadlock:
*
* (1) _threadSuspendLock (use lockThreadSuspend())
* (2) threadListLock (use dvmLockThreadList())
* (3) threadSuspendCountLock (use lockThreadSuspendCount())
*/
/*
* Thread ID bitmap. We want threads to have small integer IDs so
* we can use them in "thin locks".
*/
BitVector* threadIdMap;
/*
* Manage exit conditions. The VM exits when all non-daemon threads
* have exited. If the main thread returns early, we need to sleep
* on a condition variable.
*/
int nonDaemonThreadCount; /* must hold threadListLock to access */
//pthread_mutex_t vmExitLock;
pthread_cond_t vmExitCond;
/*
* The set of DEX files loaded by custom class loaders.
*/
HashTable* userDexFiles;
/*
* JNI global reference table.
*/
#ifdef USE_INDIRECT_REF
IndirectRefTable jniGlobalRefTable;
#else
ReferenceTable jniGlobalRefTable;
#endif
pthread_mutex_t jniGlobalRefLock;
int jniGlobalRefHiMark;
int jniGlobalRefLoMark;
/*
* JNI pinned object table (used for primitive arrays).
*/
ReferenceTable jniPinRefTable;
pthread_mutex_t jniPinRefLock;
/* special ReferenceQueue for JNI weak globals */
Object* jniWeakGlobalRefQueue;
/*
* Native shared library table.
*/
HashTable* nativeLibs;
/*
* GC heap lock. Functions like gcMalloc() acquire this before making
* any changes to the heap. It is held throughout garbage collection.
*/
pthread_mutex_t gcHeapLock;
/* Opaque pointer representing the heap. */
GcHeap* gcHeap;
/*
* Pre-allocated throwables.
*/
Object* outOfMemoryObj;
Object* internalErrorObj;
Object* noClassDefFoundErrorObj;
/* Monitor list, so we can free them */
/*volatile*/ Monitor* monitorList;
/* Monitor for Thread.sleep() implementation */
Monitor* threadSleepMon;
/* set when we create a second heap inside the zygote */
bool newZygoteHeapAllocated;
/*
* TLS keys.
*/
pthread_key_t pthreadKeySelf; /* Thread*, for dvmThreadSelf */
/*
* JNI allows you to have multiple VMs, but we limit ourselves to 1,
* so "vmList" is really just a pointer to the one and only VM.
*/
JavaVM* vmList;
/*
* Cache results of "A instanceof B".
*/
AtomicCache* instanceofCache;
/* instruction width table, used for optimization and verification */
InstructionWidth* instrWidth;
/* instruction flags table, used for verification */
InstructionFlags* instrFlags;
/* instruction format table, used for verification */
InstructionFormat* instrFormat;
/*
* Bootstrap class loader linear allocator.
*/
LinearAllocHdr* pBootLoaderAlloc;
/*
* Heap worker thread.
*/
bool heapWorkerInitialized;
bool heapWorkerReady;
bool haltHeapWorker;
pthread_t heapWorkerHandle;
pthread_mutex_t heapWorkerLock;
pthread_cond_t heapWorkerCond;
pthread_cond_t heapWorkerIdleCond;
pthread_mutex_t heapWorkerListLock;
/*
* Compute some stats on loaded classes.
*/
int numLoadedClasses;
int numDeclaredMethods;
int numDeclaredInstFields;
int numDeclaredStaticFields;
/* when using a native debugger, set this to suppress watchdog timers */
bool nativeDebuggerActive;
/*
* JDWP debugger support.
*
* Note "debuggerActive" is accessed from mterp, so its storage size and
* meaning must not be changed without updating the assembly sources.
*/
bool debuggerConnected; /* debugger or DDMS is connected */
u1 debuggerActive; /* debugger is making requests */
JdwpState* jdwpState;
/*
* Registry of objects known to the debugger.
*/
HashTable* dbgRegistry;
/*
* Debugger breakpoint table.
*/
BreakpointSet* breakpointSet;
/*
* Single-step control struct. We currently only allow one thread to
* be single-stepping at a time, which is all that really makes sense,
* but it's possible we may need to expand this to be per-thread.
*/
StepControl stepControl;
/*
* DDM features embedded in the VM.
*/
bool ddmThreadNotification;
/*
* Zygote (partially-started process) support
*/
bool zygote;
/*
* Used for tracking allocations that we report to DDMS. When the feature
* is enabled (through a DDMS request) the "allocRecords" pointer becomes
* non-NULL.
*/
pthread_mutex_t allocTrackerLock;
AllocRecord* allocRecords;
int allocRecordHead; /* most-recently-added entry */
int allocRecordCount; /* #of valid entries */
#ifdef WITH_ALLOC_LIMITS
/* set on first use of an alloc limit, never cleared */
bool checkAllocLimits;
/* allocation limit, for setGlobalAllocationLimit() regression testing */
int allocationLimit;
#endif
#ifdef WITH_DEADLOCK_PREDICTION
/* global lock on history tree accesses */
pthread_mutex_t deadlockHistoryLock;
enum { kDPOff=0, kDPWarn, kDPErr, kDPAbort } deadlockPredictMode;
#endif
#ifdef WITH_PROFILER
/*
* When a profiler is enabled, this is incremented. Distinct profilers
* include "dmtrace" method tracing, emulator method tracing, and
* possibly instruction counting.
*
* The purpose of this is to have a single value that the interpreter
* can check to see if any profiling activity is enabled.
*/
volatile int activeProfilers;
/*
* State for method-trace profiling.
*/
MethodTraceState methodTrace;
/*
* State for emulator tracing.
*/
void* emulatorTracePage;
int emulatorTraceEnableCount;
/*
* Global state for memory allocation profiling.
*/
AllocProfState allocProf;
/*
* Pointers to the original methods for things that have been inlined.
* This makes it easy for us to output method entry/exit records for
* the method calls we're not actually making.
*/
Method** inlinedMethods;
/*
* Dalvik instruction counts (256 entries).
*/
int* executedInstrCounts;
bool instructionCountEnableCount;
#endif
/*
* Signal catcher thread (for SIGQUIT).
*/
pthread_t signalCatcherHandle;
bool haltSignalCatcher;
/*
* Stdout/stderr conversion thread.
*/
bool haltStdioConverter;
bool stdioConverterReady;
pthread_t stdioConverterHandle;
pthread_mutex_t stdioConverterLock;
pthread_cond_t stdioConverterCond;
/*
* pid of the system_server process. We track it so that when system server
* crashes the Zygote process will be killed and restarted.
*/
pid_t systemServerPid;
int kernelGroupScheduling;
//#define COUNT_PRECISE_METHODS
#ifdef COUNT_PRECISE_METHODS
PointerSet* preciseMethods;
#endif
/* some RegisterMap statistics, useful during development */
void* registerMapStats;
};
extern struct DvmGlobals gDvm;
#if defined(WITH_JIT)
/*
* Exiting the compiled code w/o chaining will incur overhead to look up the
* target in the code cache which is extra work only when JIT is enabled. So
* we want to monitor it closely to make sure we don't have performance bugs.
*/
typedef enum NoChainExits {
kInlineCacheMiss = 0,
kCallsiteInterpreted,
kSwitchOverflow,
kHeavyweightMonitor,
kNoChainExitLast,
} NoChainExits;
/*
* JIT-specific global state
*/
struct DvmJitGlobals {
/*
* Guards writes to Dalvik PC (dPC), translated code address (codeAddr) and
* chain fields within the JIT hash table. Note carefully the access
* mechanism.
* Only writes are guarded, and the guarded fields must be updated in a
* specific order using atomic operations. Further, once a field is
* written it cannot be changed without halting all threads.
*
* The write order is:
* 1) codeAddr
* 2) dPC
* 3) chain [if necessary]
*
* This mutex also guards both read and write of curJitTableEntries.
*/
pthread_mutex_t tableLock;
/* The JIT hash table. Note that for access speed, copies of this pointer
* are stored in each thread. */
struct JitEntry *pJitEntryTable;
/* Array of profile threshold counters */
unsigned char *pProfTable;
/* Copy of pProfTable used for temporarily disabling the Jit */
unsigned char *pProfTableCopy;
/* Size of JIT hash table in entries. Must be a power of 2 */
unsigned int jitTableSize;
/* Mask used in hash function for JitTable. Should be jitTableSize-1 */
unsigned int jitTableMask;
/* How many entries in the JitEntryTable are in use */
unsigned int jitTableEntriesUsed;
/* Bytes allocated for the code cache */
unsigned int codeCacheSize;
/* Trigger for trace selection */
unsigned short threshold;
/* JIT Compiler Control */
bool haltCompilerThread;
bool blockingMode;
pthread_t compilerHandle;
pthread_mutex_t compilerLock;
pthread_mutex_t compilerICPatchLock;
pthread_cond_t compilerQueueActivity;
pthread_cond_t compilerQueueEmpty;
volatile int compilerQueueLength;
int compilerHighWater;
int compilerWorkEnqueueIndex;
int compilerWorkDequeueIndex;
int compilerICPatchIndex;
/* JIT internal stats */
int compilerMaxQueued;
int addrLookupsFound;
int addrLookupsNotFound;
int noChainExit[kNoChainExitLast];
int normalExit;
int puntExit;
int translationChains;
int invokeMonomorphic;
int invokePolymorphic;
int invokeNative;
int returnOp;
int icPatchFast;
int icPatchQueued;
int icPatchDropped;
u8 jitTime;
/* Compiled code cache */
void* codeCache;
/* Bytes used by the code templates */
unsigned int templateSize;
/* Bytes already used in the code cache */
unsigned int codeCacheByteUsed;
/* Number of installed compilations in the cache */
unsigned int numCompilations;
/* Flag to indicate that the code cache is full */
bool codeCacheFull;
/* Number of times that the code cache has been reset */
int numCodeCacheReset;
/* Number of times that the code cache reset request has been delayed */
int numCodeCacheResetDelayed;
/* true/false: compile/reject opcodes specified in the -Xjitop list */
bool includeSelectedOp;
/* true/false: compile/reject methods specified in the -Xjitmethod list */
bool includeSelectedMethod;
/* Disable JIT for selected opcodes - one bit for each opcode */
char opList[32];
/* Disable JIT for selected methods */
HashTable *methodTable;
/* Flag to dump all compiled code */
bool printMe;
/* Flag to count trace execution */
bool profile;
/* Vector to disable selected optimizations */
int disableOpt;
/* Code address of special interpret-only pseudo-translation */
void *interpretTemplate;
/* Table to track the overall and trace statistics of hot methods */
HashTable* methodStatsTable;
/* Filter method compilation blacklist with call-graph information */
bool checkCallGraph;
/* New translation chain has been set up */
volatile bool hasNewChain;
#if defined(WITH_SELF_VERIFICATION)
/* Spin when error is detected, volatile so GDB can reset it */
volatile bool selfVerificationSpin;
#endif
/* Framework or stand-alone? */
bool runningInAndroidFramework;
/* Framework callback happened? */
bool alreadyEnabledViaFramework;
/* Framework requests to disable the JIT for good */
bool disableJit;
#if defined(SIGNATURE_BREAKPOINT)
/* Signature breakpoint */
u4 signatureBreakpointSize; // # of words
u4 *signatureBreakpoint; // Signature content
#endif
/* Place arrays at the end to ease the display in gdb sessions */
/* Work order queue for compilations */
CompilerWorkOrder compilerWorkQueue[COMPILER_WORK_QUEUE_SIZE];
/* Work order queue for predicted chain patching */
ICPatchWorkOrder compilerICPatchQueue[COMPILER_IC_PATCH_QUEUE_SIZE];
};
extern struct DvmJitGlobals gDvmJit;
#endif
#endif /*_DALVIK_GLOBALS*/