Home | History | Annotate | Download | only in interp
      1 /*
      2  * Copyright (C) 2008 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  * Dalvik interpreter definitions.  These are internal to the interpreter.
     18  *
     19  * This includes defines, types, function declarations, and inline functions
     20  * that are common to all interpreter implementations.
     21  *
     22  * Functions and globals declared here are defined in Interp.c.
     23  */
     24 #ifndef _DALVIK_INTERP_DEFS
     25 #define _DALVIK_INTERP_DEFS
     26 
     27 
     28 /*
     29  * Specify the starting point when switching between interpreters.
     30  */
     31 typedef enum InterpEntry {
     32     kInterpEntryInstr = 0,      // continue to next instruction
     33     kInterpEntryReturn = 1,     // jump to method return
     34     kInterpEntryThrow = 2,      // jump to exception throw
     35 #if defined(WITH_JIT)
     36     kInterpEntryResume = 3,     // Resume after single-step
     37 #endif
     38 } InterpEntry;
     39 
     40 #if defined(WITH_JIT)
     41 /*
     42  * There are six entry points from the compiled code to the interpreter:
     43  * 1) dvmJitToInterpNormal: find if there is a corresponding compilation for
     44  *    the new dalvik PC. If so, chain the originating compilation with the
     45  *    target then jump to it.
     46  * 2) dvmJitToInterpInvokeNoChain: similar to 1) but don't chain. This is
     47  *    for handling 1-to-many mappings like virtual method call and
     48  *    packed switch.
     49  * 3) dvmJitToInterpPunt: use the fast interpreter to execute the next
     50  *    instruction(s) and stay there as long as it is appropriate to return
     51  *    to the compiled land. This is used when the jit'ed code is about to
     52  *    throw an exception.
     53  * 4) dvmJitToInterpSingleStep: use the portable interpreter to execute the
     54  *    next instruction only and return to pre-specified location in the
     55  *    compiled code to resume execution. This is mainly used as debugging
     56  *    feature to bypass problematic opcode implementations without
     57  *    disturbing the trace formation.
     58  * 5) dvmJitToTraceSelect: if there is a single exit from a translation that
     59  *    has already gone hot enough to be translated, we should assume that
     60  *    the exit point should also be translated (this is a common case for
     61  *    invokes).  This trace exit will first check for a chaining
     62  *    opportunity, and if none is available will switch to the debug
     63  *    interpreter immediately for trace selection (as if threshold had
     64  *    just been reached).
     65  * 6) dvmJitToPredictedChain: patch the chaining cell for a virtual call site
     66  *    to a predicted callee.
     67  * 7) dvmJitToBackwardBranch: (WITH_SELF_VERIFICATION ONLY) special case of 1)
     68  *    and 5). This is used instead if the ending branch of the trace jumps back
     69  *    into the same basic block.
     70  */
     71 struct JitToInterpEntries {
     72     void *dvmJitToInterpNormal;
     73     void *dvmJitToInterpNoChain;
     74     void *dvmJitToInterpPunt;
     75     void *dvmJitToInterpSingleStep;
     76     void *dvmJitToInterpTraceSelectNoChain;
     77     void *dvmJitToInterpTraceSelect;
     78     void *dvmJitToPatchPredictedChain;
     79 #if defined(WITH_SELF_VERIFICATION)
     80     void *dvmJitToInterpBackwardBranch;
     81 #endif
     82 };
     83 
     84 /*
     85  * Size of save area for callee-save FP regs, which are not automatically
     86  * saved by interpreter main because it doesn't use them (but Jit'd code
     87  * may). Save/restore routine is defined by target, and size should
     88  * be >= max needed by any target.
     89  */
     90 #define JIT_CALLEE_SAVE_DOUBLE_COUNT 8
     91 
     92 /* Number of entries in the 2nd level JIT profiler filter cache */
     93 #define JIT_TRACE_THRESH_FILTER_SIZE 32
     94 /* Number of low dalvik pc address bits to include in 2nd level filter key */
     95 #define JIT_TRACE_THRESH_FILTER_PC_BITS 4
     96 #endif
     97 
     98 /*
     99  * Interpreter context, used when switching from one interpreter to
    100  * another.  We also tuck "mterp" state in here.
    101  */
    102 typedef struct InterpState {
    103     /*
    104      * To make some mterp state updates easier, "pc" and "fp" MUST come
    105      * first and MUST appear in this order.
    106      */
    107     const u2*   pc;                     // program counter
    108     u4*         fp;                     // frame pointer
    109 
    110     JValue      retval;                 // return value -- "out" only
    111     const Method* method;               // method being executed
    112 
    113 
    114     /* ----------------------------------------------------------------------
    115      * Mterp-only state
    116      */
    117     DvmDex*         methodClassDex;
    118     Thread*         self;
    119 
    120     /* housekeeping */
    121     void*           bailPtr;
    122 
    123     /*
    124      * These are available globally, from gDvm, or from another glue field
    125      * (self/method).  They're copied in here for speed.
    126      */
    127     /* copy of self->interpStackEnd */
    128     const u1*       interpStackEnd;
    129     /* points at self->suspendCount */
    130     volatile int*   pSelfSuspendCount;
    131     /* Biased base of GC's card table */
    132     u1*             cardTable;
    133     /* points at gDvm.debuggerActive, or NULL if debugger not enabled */
    134     volatile u1*    pDebuggerActive;
    135     /* points at gDvm.activeProfilers */
    136     volatile int*   pActiveProfilers;
    137     /* ----------------------------------------------------------------------
    138      */
    139 
    140     /*
    141      * Interpreter switching.
    142      */
    143     InterpEntry entryPoint;             // what to do when we start
    144     int         nextMode;               // INTERP_STD, INTERP_DBG
    145 
    146 #if defined(WITH_JIT)
    147     /*
    148      * Local copies of field from gDvm placed here for fast access
    149      */
    150     unsigned char*     pJitProfTable;
    151     JitState           jitState;
    152     const void*        jitResumeNPC;    // Native PC of compiled code
    153     const u2*          jitResumeDPC;    // Dalvik PC corresponding to NPC
    154     int                jitThreshold;
    155     /*
    156      * ppJitProfTable holds the address of gDvmJit.pJitProfTable, which
    157      * doubles as an on/off switch for the Jit.  Because a change in
    158      * the value of gDvmJit.pJitProfTable isn't reflected in the cached
    159      * copy above (pJitProfTable), we need to periodically refresh it.
    160      * ppJitProfTable is used for that purpose.
    161      */
    162     unsigned char**    ppJitProfTable; // Used to refresh pJitProfTable
    163     int                icRechainCount; // Count down to next rechain request
    164 #endif
    165 
    166     bool        debugIsMethodEntry;     // used for method entry event triggers
    167 #if defined(WITH_TRACKREF_CHECKS)
    168     int         debugTrackedRefStart;   // tracked refs from prior invocations
    169 #endif
    170 
    171 #if defined(WITH_JIT)
    172     struct JitToInterpEntries jitToInterpEntries;
    173 
    174     int currTraceRun;
    175     int totalTraceLen;        // Number of Dalvik insts in trace
    176     const u2* currTraceHead;  // Start of the trace we're building
    177     const u2* currRunHead;    // Start of run we're building
    178     int currRunLen;           // Length of run in 16-bit words
    179     int lastThreshFilter;
    180     const u2* lastPC;         // Stage the PC first for the threaded interpreter
    181     intptr_t threshFilter[JIT_TRACE_THRESH_FILTER_SIZE];
    182     JitTraceRun trace[MAX_JIT_RUN_LEN];
    183     double calleeSave[JIT_CALLEE_SAVE_DOUBLE_COUNT];
    184 #endif
    185 
    186 } InterpState;
    187 
    188 /*
    189  * These are generated from InterpCore.h.
    190  */
    191 extern bool dvmInterpretDbg(Thread* self, InterpState* interpState);
    192 extern bool dvmInterpretStd(Thread* self, InterpState* interpState);
    193 #define INTERP_STD 0
    194 #define INTERP_DBG 1
    195 
    196 /*
    197  * "mterp" interpreter.
    198  */
    199 extern bool dvmMterpStd(Thread* self, InterpState* interpState);
    200 
    201 /*
    202  * Get the "this" pointer from the current frame.
    203  */
    204 Object* dvmGetThisPtr(const Method* method, const u4* fp);
    205 
    206 /*
    207  * Verify that our tracked local references are valid.
    208  */
    209 void dvmInterpCheckTrackedRefs(Thread* self, const Method* method,
    210     int debugTrackedRefStart);
    211 
    212 /*
    213  * Process switch statement.
    214  */
    215 s4 dvmInterpHandlePackedSwitch(const u2* switchData, s4 testVal);
    216 s4 dvmInterpHandleSparseSwitch(const u2* switchData, s4 testVal);
    217 
    218 /*
    219  * Process fill-array-data.
    220  */
    221 bool dvmInterpHandleFillArrayData(ArrayObject* arrayObject,
    222                                   const u2* arrayData);
    223 
    224 /*
    225  * Find an interface method.
    226  */
    227 Method* dvmInterpFindInterfaceMethod(ClassObject* thisClass, u4 methodIdx,
    228     const Method* method, DvmDex* methodClassDex);
    229 
    230 /*
    231  * Determine if the debugger or profiler is currently active.  Used when
    232  * selecting which interpreter to start or switch to.
    233  */
    234 static inline bool dvmDebuggerOrProfilerActive(void)
    235 {
    236     return gDvm.debuggerActive || gDvm.activeProfilers != 0;
    237 }
    238 
    239 #if defined(WITH_JIT)
    240 /*
    241  * Determine if the jit, debugger or profiler is currently active.  Used when
    242  * selecting which interpreter to switch to.
    243  */
    244 static inline bool dvmJitDebuggerOrProfilerActive()
    245 {
    246     return gDvmJit.pProfTable != NULL
    247         || gDvm.activeProfilers != 0
    248         || gDvm.debuggerActive;
    249 }
    250 
    251 /*
    252  * Hide the translations and stick with the interpreter as long as one of the
    253  * following conditions is true.
    254  */
    255 static inline bool dvmJitHideTranslation()
    256 {
    257     return (gDvm.sumThreadSuspendCount != 0) ||
    258            (gDvmJit.codeCacheFull == true) ||
    259            (gDvmJit.pProfTable == NULL);
    260 }
    261 
    262 /*
    263  * The fast and debug interpreter may be doing ping-pong without making forward
    264  * progress if the same trace building request sent upon entering the fast
    265  * interpreter is rejected immediately by the debug interpreter. Use the
    266  * following function to poll the rejection reasons and stay in the debug
    267  * interpreter until they are cleared. This will guarantee forward progress
    268  * in the extreme corner cases (eg set compiler threashold to 1).
    269  */
    270 static inline bool dvmJitStayInPortableInterpreter()
    271 {
    272     return dvmJitHideTranslation() ||
    273            (gDvmJit.compilerQueueLength >= gDvmJit.compilerHighWater);
    274 }
    275 #endif
    276 
    277 #endif /*_DALVIK_INTERP_DEFS*/
    278