Compiler.h revision 18fba346582c08d81aa96d9508c0e935bad5f36f
1/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <Thread.h>
18#include <setjmp.h>
19
20#ifndef _DALVIK_VM_COMPILER
21#define _DALVIK_VM_COMPILER
22
23/*
24 * Uncomment the following to enable JIT signature breakpoint
25 * #define SIGNATURE_BREAKPOINT
26 */
27
28#define MAX_JIT_RUN_LEN                 64
29#define COMPILER_WORK_QUEUE_SIZE        100
30#define COMPILER_IC_PATCH_QUEUE_SIZE    64
31
32/* Architectural-independent parameters for predicted chains */
33#define PREDICTED_CHAIN_CLAZZ_INIT       0
34#define PREDICTED_CHAIN_METHOD_INIT      0
35#define PREDICTED_CHAIN_COUNTER_INIT     0
36/* A fake value which will avoid initialization and won't match any class */
37#define PREDICTED_CHAIN_FAKE_CLAZZ       0xdeadc001
38/* Has to be positive */
39#define PREDICTED_CHAIN_COUNTER_AVOID    0x7fffffff
40/* Rechain after this many misses - shared globally and has to be positive */
41#define PREDICTED_CHAIN_COUNTER_RECHAIN  8192
42
43#define COMPILER_TRACED(X)
44#define COMPILER_TRACEE(X)
45#define COMPILER_TRACE_CHAINING(X)
46
47/* Macro to change the permissions applied to a chunk of the code cache */
48#define PROTECT_CODE_CACHE_ATTRS       (PROT_READ | PROT_EXEC)
49#define UNPROTECT_CODE_CACHE_ATTRS     (PROT_READ | PROT_EXEC | PROT_WRITE)
50
51/* Acquire the lock before removing PROT_WRITE from the specified mem region */
52#define UNPROTECT_CODE_CACHE(addr, size)                                       \
53    {                                                                          \
54        dvmLockMutex(&gDvmJit.codeCacheProtectionLock);                        \
55        mprotect((void *) (((intptr_t) (addr)) & ~gDvmJit.pageSizeMask),       \
56                 (size) + (((intptr_t) (addr)) & gDvmJit.pageSizeMask),        \
57                 (UNPROTECT_CODE_CACHE_ATTRS));                                \
58    }
59
60/* Add the PROT_WRITE to the specified memory region then release the lock */
61#define PROTECT_CODE_CACHE(addr, size)                                         \
62    {                                                                          \
63        mprotect((void *) (((intptr_t) (addr)) & ~gDvmJit.pageSizeMask),       \
64                 (size) + (((intptr_t) (addr)) & gDvmJit.pageSizeMask),        \
65                 (PROTECT_CODE_CACHE_ATTRS));                                  \
66        dvmUnlockMutex(&gDvmJit.codeCacheProtectionLock);                      \
67    }
68
69#define SINGLE_STEP_OP(opcode)                                                 \
70    (gDvmJit.includeSelectedOp !=                                              \
71     ((gDvmJit.opList[opcode >> 3] & (1 << (opcode & 0x7))) != 0))
72
73typedef enum JitInstructionSetType {
74    DALVIK_JIT_NONE = 0,
75    DALVIK_JIT_ARM,
76    DALVIK_JIT_THUMB,
77    DALVIK_JIT_THUMB2,
78    DALVIK_JIT_THUMB2EE,
79    DALVIK_JIT_IA32
80} JitInstructionSetType;
81
82/* Description of a compiled trace. */
83typedef struct JitTranslationInfo {
84    void *codeAddress;
85    JitInstructionSetType instructionSet;
86    int profileCodeSize;
87    bool discardResult;         // Used for debugging divergence and IC patching
88    bool methodCompilationAborted;  // Cannot compile the whole method
89    Thread *requestingThread;   // For debugging purpose
90    int cacheVersion;           // Used to identify stale trace requests
91} JitTranslationInfo;
92
93typedef enum WorkOrderKind {
94    kWorkOrderInvalid = 0,      // Should never see by the backend
95    kWorkOrderMethod = 1,       // Work is to compile a whole method
96    kWorkOrderTrace = 2,        // Work is to compile code fragment(s)
97    kWorkOrderTraceDebug = 3,   // Work is to compile/debug code fragment(s)
98    kWorkOrderProfileMode = 4,  // Change profiling mode
99} WorkOrderKind;
100
101typedef struct CompilerWorkOrder {
102    const u2* pc;
103    WorkOrderKind kind;
104    void* info;
105    JitTranslationInfo result;
106    jmp_buf *bailPtr;
107} CompilerWorkOrder;
108
109/* Chain cell for predicted method invocation */
110typedef struct PredictedChainingCell {
111    u4 branch;                  /* Branch to chained destination */
112    const ClassObject *clazz;   /* key for prediction */
113    const Method *method;       /* to lookup native PC from dalvik PC */
114    const ClassObject *stagedClazz;   /* possible next key for prediction */
115} PredictedChainingCell;
116
117/* Work order for inline cache patching */
118typedef struct ICPatchWorkOrder {
119    PredictedChainingCell *cellAddr;    /* Address to be patched */
120    PredictedChainingCell cellContent;  /* content of the new cell */
121} ICPatchWorkOrder;
122
123/* States of the dbg interpreter when serving a JIT-related request */
124typedef enum JitState {
125    /* Entering states in the debug interpreter */
126    kJitNot = 0,               // Non-JIT related reasons */
127    kJitTSelectRequest = 1,    // Request a trace (subject to filtering)
128    kJitTSelectRequestHot = 2, // Request a hot trace (bypass the filter)
129    kJitSelfVerification = 3,  // Self Verification Mode
130
131    /* Operational states in the debug interpreter */
132    kJitTSelect = 4,           // Actively selecting a trace
133    kJitTSelectEnd = 5,        // Done with the trace - wrap it up
134    kJitSingleStep = 6,        // Single step interpretation
135    kJitSingleStepEnd = 7,     // Done with single step, ready return to mterp
136    kJitDone = 8,              // Ready to leave the debug interpreter
137} JitState;
138
139#if defined(WITH_SELF_VERIFICATION)
140typedef enum SelfVerificationState {
141    kSVSIdle = 0,           // Idle
142    kSVSStart = 1,          // Shadow space set up, running compiled code
143    kSVSPunt = 2,           // Exiting compiled code by punting
144    kSVSSingleStep = 3,     // Exiting compiled code by single stepping
145    kSVSNoProfile = 4,      // Exiting compiled code and don't collect profiles
146    kSVSTraceSelect = 5,    // Exiting compiled code and compile the next pc
147    kSVSNormal = 6,         // Exiting compiled code normally
148    kSVSNoChain = 7,        // Exiting compiled code by no chain
149    kSVSBackwardBranch = 8, // Exiting compiled code with backward branch trace
150    kSVSDebugInterp = 9,    // Normal state restored, running debug interpreter
151} SelfVerificationState;
152#endif
153
154typedef enum JitHint {
155   kJitHintNone = 0,
156   kJitHintTaken = 1,         // Last inst in run was taken branch
157   kJitHintNotTaken = 2,      // Last inst in run was not taken branch
158   kJitHintNoBias = 3,        // Last inst in run was unbiased branch
159} jitHint;
160
161/*
162 * Element of a Jit trace description. If the isCode bit is set, it describes
163 * a contiguous sequence of Dalvik byte codes.
164 */
165typedef struct {
166    unsigned isCode:1;       // If set denotes code fragments
167    unsigned numInsts:8;     // Number of Byte codes in run
168    unsigned runEnd:1;       // Run ends with last byte code
169    jitHint  hint:6;         // Hint to apply to final code of run
170    u2    startOffset;       // Starting offset for trace run
171} JitCodeDesc;
172
173/*
174 * A complete list of trace runs passed to the compiler looks like the
175 * following:
176 *   frag1
177 *   frag2
178 *   frag3
179 *   meta1
180 *   meta2
181 *   frag4
182 *
183 * frags 1-4 have the "isCode" field set, and metas 1-2 are plain pointers or
184 * pointers to auxiliary data structures as long as the LSB is null.
185 * The meaning of the meta content is loosely defined. It is usually the code
186 * fragment right before the first meta field (frag3 in this case) to
187 * understand and parse them. Frag4 could be a dummy one with 0 "numInsts" but
188 * the "runEnd" field set.
189 *
190 * For example, if a trace run contains a method inlining target, the class
191 * type of "this" and the currently resolved method pointer are two instances
192 * of meta information stored there.
193 */
194typedef union {
195    JitCodeDesc frag;
196    void*       meta;
197} JitTraceRun;
198
199/*
200 * Trace description as will appear in the translation cache.  Note
201 * flexible array at end, as these will be of variable size.  To
202 * conserve space in the translation cache, total length of JitTraceRun
203 * array must be recomputed via seqential scan if needed.
204 */
205typedef struct {
206    const Method* method;
207    JitTraceRun trace[0];       // Variable-length trace descriptors
208} JitTraceDescription;
209
210typedef enum JitMethodAttributes {
211    kIsCallee = 0,      /* Code is part of a callee (invoked by a hot trace) */
212    kIsHot,             /* Code is part of a hot trace */
213    kIsLeaf,            /* Method is leaf */
214    kIsEmpty,           /* Method is empty */
215    kIsThrowFree,       /* Method doesn't throw */
216    kIsGetter,          /* Method fits the getter pattern */
217    kIsSetter,          /* Method fits the setter pattern */
218} JitMethodAttributes;
219
220#define METHOD_IS_CALLEE        (1 << kIsCallee)
221#define METHOD_IS_HOT           (1 << kIsHot)
222#define METHOD_IS_LEAF          (1 << kIsLeaf)
223#define METHOD_IS_EMPTY         (1 << kIsEmpty)
224#define METHOD_IS_THROW_FREE    (1 << kIsThrowFree)
225#define METHOD_IS_GETTER        (1 << kIsGetter)
226#define METHOD_IS_SETTER        (1 << kIsSetter)
227
228/* Vectors to provide optimization hints */
229typedef enum JitOptimizationHints {
230    kJitOptNoLoop = 0,          // Disable loop formation/optimization
231} JitOptimizationHints;
232
233#define JIT_OPT_NO_LOOP         (1 << kJitOptNoLoop)
234
235/* Customized node traversal orders for different needs */
236typedef enum DataFlowAnalysisMode {
237    kAllNodes = 0,              // All nodes
238    kReachableNodes,            // All reachable nodes
239    kPreOrderDFSTraversal,      // Depth-First-Search / Pre-Order
240    kPostOrderDFSTraversal,     // Depth-First-Search / Post-Order
241    kPostOrderDOMTraversal,     // Dominator tree / Post-Order
242} DataFlowAnalysisMode;
243
244typedef struct CompilerMethodStats {
245    const Method *method;       // Used as hash entry signature
246    int dalvikSize;             // # of bytes for dalvik bytecodes
247    int compiledDalvikSize;     // # of compiled dalvik bytecodes
248    int nativeSize;             // # of bytes for produced native code
249    int attributes;             // attribute vector
250} CompilerMethodStats;
251
252struct CompilationUnit;
253struct BasicBlock;
254struct SSARepresentation;
255struct GrowableList;
256struct JitEntry;
257struct MIR;
258
259bool dvmCompilerSetupCodeCache(void);
260bool dvmCompilerArchInit(void);
261void dvmCompilerArchDump(void);
262bool dvmCompilerStartup(void);
263void dvmCompilerShutdown(void);
264bool dvmCompilerWorkEnqueue(const u2* pc, WorkOrderKind kind, void* info);
265void *dvmCheckCodeCache(void *method);
266CompilerMethodStats *dvmCompilerAnalyzeMethodBody(const Method *method,
267                                                  bool isCallee);
268bool dvmCompilerCanIncludeThisInstruction(const Method *method,
269                                          const DecodedInstruction *insn);
270bool dvmCompileMethod(const Method *method);
271bool dvmCompileTrace(JitTraceDescription *trace, int numMaxInsts,
272                     JitTranslationInfo *info, jmp_buf *bailPtr, int optHints);
273void dvmCompilerDumpStats(void);
274void dvmCompilerDrainQueue(void);
275void dvmJitUnchainAll(void);
276void dvmCompilerSortAndPrintTraceProfiles(void);
277void dvmCompilerPerformSafePointChecks(void);
278void dvmCompilerInlineMIR(struct CompilationUnit *cUnit);
279void dvmInitializeSSAConversion(struct CompilationUnit *cUnit);
280int dvmConvertSSARegToDalvik(const struct CompilationUnit *cUnit, int ssaReg);
281bool dvmCompilerLoopOpt(struct CompilationUnit *cUnit);
282void dvmCompilerNonLoopAnalysis(struct CompilationUnit *cUnit);
283bool dvmCompilerFindLocalLiveIn(struct CompilationUnit *cUnit,
284                                struct BasicBlock *bb);
285bool dvmCompilerDoSSAConversion(struct CompilationUnit *cUnit,
286                                struct BasicBlock *bb);
287bool dvmCompilerDoConstantPropagation(struct CompilationUnit *cUnit,
288                                      struct BasicBlock *bb);
289bool dvmCompilerFindInductionVariables(struct CompilationUnit *cUnit,
290                                       struct BasicBlock *bb);
291/* Clear the visited flag for each BB */
292bool dvmCompilerClearVisitedFlag(struct CompilationUnit *cUnit,
293                                 struct BasicBlock *bb);
294char *dvmCompilerGetDalvikDisassembly(const DecodedInstruction *insn,
295                                      char *note);
296char *dvmCompilerFullDisassembler(const struct CompilationUnit *cUnit,
297                                  const struct MIR *mir);
298char *dvmCompilerGetSSAString(struct CompilationUnit *cUnit,
299                              struct SSARepresentation *ssaRep);
300void dvmCompilerDataFlowAnalysisDispatcher(struct CompilationUnit *cUnit,
301                bool (*func)(struct CompilationUnit *, struct BasicBlock *),
302                DataFlowAnalysisMode dfaMode,
303                bool isIterative);
304void dvmCompilerMethodSSATransformation(struct CompilationUnit *cUnit);
305void dvmCompilerStateRefresh(void);
306JitTraceDescription *dvmCopyTraceDescriptor(const u2 *pc,
307                                            const struct JitEntry *desc);
308void *dvmCompilerGetInterpretTemplate();
309#endif /* _DALVIK_VM_COMPILER */
310