/* * Copyright (C) 2009 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. */ #include <Thread.h> #include <setjmp.h> #ifndef _DALVIK_VM_COMPILER #define _DALVIK_VM_COMPILER /* * Uncomment the following to enable JIT signature breakpoint * #define SIGNATURE_BREAKPOINT */ #define MAX_JIT_RUN_LEN 64 #define COMPILER_WORK_QUEUE_SIZE 100 #define COMPILER_IC_PATCH_QUEUE_SIZE 64 /* Architectural-independent parameters for predicted chains */ #define PREDICTED_CHAIN_CLAZZ_INIT 0 #define PREDICTED_CHAIN_METHOD_INIT 0 #define PREDICTED_CHAIN_COUNTER_INIT 0 /* A fake value which will avoid initialization and won't match any class */ #define PREDICTED_CHAIN_FAKE_CLAZZ 0xdeadc001 /* Has to be positive */ #define PREDICTED_CHAIN_COUNTER_AVOID 0x7fffffff /* Rechain after this many misses - shared globally and has to be positive */ #define PREDICTED_CHAIN_COUNTER_RECHAIN 8192 #define COMPILER_TRACED(X) #define COMPILER_TRACEE(X) #define COMPILER_TRACE_CHAINING(X) /* Macro to change the permissions applied to a chunk of the code cache */ #if !defined(WITH_JIT_TUNING) #define PROTECT_CODE_CACHE_ATTRS (PROT_READ | PROT_EXEC) #define UNPROTECT_CODE_CACHE_ATTRS (PROT_READ | PROT_EXEC | PROT_WRITE) #else /* When doing JIT profiling always grant the write permission */ #define PROTECT_CODE_CACHE_ATTRS (PROT_READ | PROT_EXEC | \ (gDvmJit.profile ? PROT_WRITE : 0)) #define UNPROTECT_CODE_CACHE_ATTRS (PROT_READ | PROT_EXEC | PROT_WRITE) #endif /* Acquire the lock before removing PROT_WRITE from the specified mem region */ #define UNPROTECT_CODE_CACHE(addr, size) \ { \ dvmLockMutex(&gDvmJit.codeCacheProtectionLock); \ mprotect((void *) (((intptr_t) (addr)) & ~gDvmJit.pageSizeMask), \ (size) + (((intptr_t) (addr)) & gDvmJit.pageSizeMask), \ (UNPROTECT_CODE_CACHE_ATTRS)); \ } /* Add the PROT_WRITE to the specified memory region then release the lock */ #define PROTECT_CODE_CACHE(addr, size) \ { \ mprotect((void *) (((intptr_t) (addr)) & ~gDvmJit.pageSizeMask), \ (size) + (((intptr_t) (addr)) & gDvmJit.pageSizeMask), \ (PROTECT_CODE_CACHE_ATTRS)); \ dvmUnlockMutex(&gDvmJit.codeCacheProtectionLock); \ } #define SINGLE_STEP_OP(opcode) \ (gDvmJit.includeSelectedOp != \ ((gDvmJit.opList[opcode >> 3] & (1 << (opcode & 0x7))) != 0)) typedef enum JitInstructionSetType { DALVIK_JIT_NONE = 0, DALVIK_JIT_ARM, DALVIK_JIT_THUMB, DALVIK_JIT_THUMB2, DALVIK_JIT_THUMB2EE, DALVIK_JIT_X86 } JitInstructionSetType; /* Description of a compiled trace. */ typedef struct JitTranslationInfo { void *codeAddress; JitInstructionSetType instructionSet; bool discardResult; // Used for debugging divergence and IC patching bool methodCompilationAborted; // Cannot compile the whole method Thread *requestingThread; // For debugging purpose } JitTranslationInfo; typedef enum WorkOrderKind { kWorkOrderInvalid = 0, // Should never see by the backend kWorkOrderMethod = 1, // Work is to compile a whole method kWorkOrderTrace = 2, // Work is to compile code fragment(s) kWorkOrderTraceDebug = 3, // Work is to compile/debug code fragment(s) } WorkOrderKind; typedef struct CompilerWorkOrder { const u2* pc; WorkOrderKind kind; void* info; JitTranslationInfo result; jmp_buf *bailPtr; } CompilerWorkOrder; /* Chain cell for predicted method invocation */ typedef struct PredictedChainingCell { u4 branch; /* Branch to chained destination */ const ClassObject *clazz; /* key for prediction */ const Method *method; /* to lookup native PC from dalvik PC */ const ClassObject *stagedClazz; /* possible next key for prediction */ } PredictedChainingCell; /* Work order for inline cache patching */ typedef struct ICPatchWorkOrder { PredictedChainingCell *cellAddr; /* Address to be patched */ PredictedChainingCell cellContent; /* content of the new cell */ } ICPatchWorkOrder; /* States of the dbg interpreter when serving a JIT-related request */ typedef enum JitState { /* Entering states in the debug interpreter */ kJitNot = 0, // Non-JIT related reasons */ kJitTSelectRequest = 1, // Request a trace (subject to filtering) kJitTSelectRequestHot = 2, // Request a hot trace (bypass the filter) kJitSelfVerification = 3, // Self Verification Mode /* Operational states in the debug interpreter */ kJitTSelect = 4, // Actively selecting a trace kJitTSelectEnd = 5, // Done with the trace - wrap it up kJitSingleStep = 6, // Single step interpretation kJitSingleStepEnd = 7, // Done with single step, ready return to mterp kJitDone = 8, // Ready to leave the debug interpreter } JitState; #if defined(WITH_SELF_VERIFICATION) typedef enum SelfVerificationState { kSVSIdle = 0, // Idle kSVSStart = 1, // Shadow space set up, running compiled code kSVSPunt = 2, // Exiting compiled code by punting kSVSSingleStep = 3, // Exiting compiled code by single stepping kSVSNoProfile = 4, // Exiting compiled code and don't collect profiles kSVSTraceSelect = 5, // Exiting compiled code and compile the next pc kSVSNormal = 6, // Exiting compiled code normally kSVSNoChain = 7, // Exiting compiled code by no chain kSVSBackwardBranch = 8, // Exiting compiled code with backward branch trace kSVSDebugInterp = 9, // Normal state restored, running debug interpreter } SelfVerificationState; #endif typedef enum JitHint { kJitHintNone = 0, kJitHintTaken = 1, // Last inst in run was taken branch kJitHintNotTaken = 2, // Last inst in run was not taken branch kJitHintNoBias = 3, // Last inst in run was unbiased branch } jitHint; /* * Element of a Jit trace description. If the isCode bit is set, it describes * a contiguous sequence of Dalvik byte codes. */ typedef struct { unsigned isCode:1; // If set denotes code fragments unsigned numInsts:8; // Number of Byte codes in run unsigned runEnd:1; // Run ends with last byte code jitHint hint:6; // Hint to apply to final code of run u2 startOffset; // Starting offset for trace run } JitCodeDesc; /* * A complete list of trace runs passed to the compiler looks like the * following: * frag1 * frag2 * frag3 * meta1 * meta2 * frag4 * * frags 1-4 have the "isCode" field set, and metas 1-2 are plain pointers or * pointers to auxiliary data structures as long as the LSB is null. * The meaning of the meta content is loosely defined. It is usually the code * fragment right before the first meta field (frag3 in this case) to * understand and parse them. Frag4 could be a dummy one with 0 "numInsts" but * the "runEnd" field set. * * For example, if a trace run contains a method inlining target, the class * type of "this" and the currently resolved method pointer are two instances * of meta information stored there. */ typedef union { JitCodeDesc frag; void* meta; } JitTraceRun; /* * Trace description as will appear in the translation cache. Note * flexible array at end, as these will be of variable size. To * conserve space in the translation cache, total length of JitTraceRun * array must be recomputed via seqential scan if needed. */ typedef struct { const Method* method; JitTraceRun trace[0]; // Variable-length trace descriptors } JitTraceDescription; typedef enum JitMethodAttributes { kIsCallee = 0, /* Code is part of a callee (invoked by a hot trace) */ kIsHot, /* Code is part of a hot trace */ kIsLeaf, /* Method is leaf */ kIsEmpty, /* Method is empty */ kIsThrowFree, /* Method doesn't throw */ kIsGetter, /* Method fits the getter pattern */ kIsSetter, /* Method fits the setter pattern */ } JitMethodAttributes; #define METHOD_IS_CALLEE (1 << kIsCallee) #define METHOD_IS_HOT (1 << kIsHot) #define METHOD_IS_LEAF (1 << kIsLeaf) #define METHOD_IS_EMPTY (1 << kIsEmpty) #define METHOD_IS_THROW_FREE (1 << kIsThrowFree) #define METHOD_IS_GETTER (1 << kIsGetter) #define METHOD_IS_SETTER (1 << kIsSetter) /* Vectors to provide optimization hints */ typedef enum JitOptimizationHints { kJitOptNoLoop = 0, // Disable loop formation/optimization } JitOptimizationHints; #define JIT_OPT_NO_LOOP (1 << kJitOptNoLoop) typedef struct CompilerMethodStats { const Method *method; // Used as hash entry signature int dalvikSize; // # of bytes for dalvik bytecodes int compiledDalvikSize; // # of compiled dalvik bytecodes int nativeSize; // # of bytes for produced native code int attributes; // attribute vector } CompilerMethodStats; struct CompilationUnit; struct BasicBlock; struct SSARepresentation; struct GrowableList; struct JitEntry; struct MIR; bool dvmCompilerSetupCodeCache(void); bool dvmCompilerArchInit(void); void dvmCompilerArchDump(void); bool dvmCompilerStartup(void); void dvmCompilerShutdown(void); bool dvmCompilerWorkEnqueue(const u2* pc, WorkOrderKind kind, void* info); void *dvmCheckCodeCache(void *method); CompilerMethodStats *dvmCompilerAnalyzeMethodBody(const Method *method, bool isCallee); bool dvmCompilerCanIncludeThisInstruction(const Method *method, const DecodedInstruction *insn); bool dvmCompileMethod(struct CompilationUnit *cUnit, const Method *method, JitTranslationInfo *info); bool dvmCompileTrace(JitTraceDescription *trace, int numMaxInsts, JitTranslationInfo *info, jmp_buf *bailPtr, int optHints); void dvmCompilerDumpStats(void); void dvmCompilerDrainQueue(void); void dvmJitUnchainAll(void); void dvmCompilerSortAndPrintTraceProfiles(void); void dvmCompilerPerformSafePointChecks(void); void dvmCompilerInlineMIR(struct CompilationUnit *cUnit); void dvmInitializeSSAConversion(struct CompilationUnit *cUnit); int dvmConvertSSARegToDalvik(struct CompilationUnit *cUnit, int ssaReg); bool dvmCompilerLoopOpt(struct CompilationUnit *cUnit); void dvmCompilerNonLoopAnalysis(struct CompilationUnit *cUnit); void dvmCompilerFindLiveIn(struct CompilationUnit *cUnit, struct BasicBlock *bb); void dvmCompilerDoSSAConversion(struct CompilationUnit *cUnit, struct BasicBlock *bb); void dvmCompilerDoConstantPropagation(struct CompilationUnit *cUnit, struct BasicBlock *bb); void dvmCompilerFindInductionVariables(struct CompilationUnit *cUnit, struct BasicBlock *bb); char *dvmCompilerGetDalvikDisassembly(DecodedInstruction *insn, char *note); char *dvmCompilerGetSSAString(struct CompilationUnit *cUnit, struct SSARepresentation *ssaRep); void dvmCompilerDataFlowAnalysisDispatcher(struct CompilationUnit *cUnit, void (*func)(struct CompilationUnit *, struct BasicBlock *)); void dvmCompilerStateRefresh(void); JitTraceDescription *dvmCopyTraceDescriptor(const u2 *pc, const struct JitEntry *desc); void *dvmCompilerGetInterpretTemplate(); #endif /* _DALVIK_VM_COMPILER */