/*
* Copyright (C) 2011 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.
*/
/*
* Dalvik interpreter definitions. These are internal to the interpreter.
*
* This includes defines, types, function declarations, and inline functions
* that are common to all interpreter implementations.
*
* Functions and globals declared here are defined in Interp.c.
*/
#ifndef DALVIK_INTERP_STATE_H_
#define DALVIK_INTERP_STATE_H_
/*
* Execution mode, e.g. interpreter vs. JIT.
*/
enum ExecutionMode {
kExecutionModeUnknown = 0,
kExecutionModeInterpPortable,
kExecutionModeInterpFast,
#if defined(WITH_JIT)
kExecutionModeJit,
#endif
};
/*
* Execution sub modes, e.g. debugging, profiling, etc.
* Treated as bit flags for fast access. These values are used directly
* by assembly code in the mterp interpeter and may also be used by
* code generated by the JIT. Take care when changing.
*/
enum ExecutionSubModes {
kSubModeNormal = 0x0000, /* No active subMode */
kSubModeMethodTrace = 0x0001,
kSubModeEmulatorTrace = 0x0002,
kSubModeInstCounting = 0x0004,
kSubModeDebuggerActive = 0x0008,
kSubModeSuspendPending = 0x0010,
kSubModeCallbackPending = 0x0020,
kSubModeCountedStep = 0x0040,
kSubModeCheckAlways = 0x0080,
kSubModeJitTraceBuild = 0x4000,
kSubModeJitSV = 0x8000,
kSubModeDebugProfile = (kSubModeMethodTrace |
kSubModeEmulatorTrace |
kSubModeInstCounting |
kSubModeDebuggerActive)
};
/*
* Interpreter break flags. When set, causes the interpreter to
* break from normal execution and invoke the associated callback
* handler.
*/
enum InterpBreakFlags {
kInterpNoBreak = 0x00, /* Don't check */
kInterpSingleStep = 0x01, /* Check between each inst */
kInterpSafePoint = 0x02, /* Check at safe points */
};
/*
* Mapping between subModes and required check intervals. Note: in
* the future we might want to make this mapping target-dependent.
*/
#define SINGLESTEP_BREAK_MASK ( kSubModeInstCounting | \
kSubModeDebuggerActive | \
kSubModeCountedStep | \
kSubModeCheckAlways | \
kSubModeJitSV | \
kSubModeJitTraceBuild )
#define SAFEPOINT_BREAK_MASK ( kSubModeSuspendPending | \
kSubModeCallbackPending )
typedef bool (*SafePointCallback)(struct Thread* thread, void* arg);
/*
* Identify which break and submode flags should be local
* to an interpreter activation.
*/
#define LOCAL_SUBMODE (kSubModeJitTraceBuild)
struct InterpSaveState {
const u2* pc; // Dalvik PC
u4* curFrame; // Dalvik frame pointer
const Method *method; // Method being executed
DvmDex* methodClassDex;
JValue retval;
void* bailPtr;
#if defined(WITH_TRACKREF_CHECKS)
int debugTrackedRefStart;
#else
int unused; // Keep struct size constant
#endif
struct InterpSaveState* prev; // To follow nested activations
} __attribute__ ((__packed__));
#ifdef WITH_JIT
/*
* NOTE: Only entry points dispatched via [self + #offset] are put
* in this struct, and there are six of them:
* 1) dvmJitToInterpNormal: find if there is a corresponding compilation for
* the new dalvik PC. If so, chain the originating compilation with the
* target then jump to it. If the destination trace doesn't exist, update
* the profile count for that Dalvik PC.
* 2) dvmJitToInterpNoChain: similar to dvmJitToInterpNormal but chaining is
* not performed.
* 3) dvmJitToInterpPunt: use the fast interpreter to execute the next
* instruction(s) and stay there as long as it is appropriate to return
* to the compiled land. This is used when the jit'ed code is about to
* throw an exception.
* 4) dvmJitToInterpSingleStep: use the portable interpreter to execute the
* next instruction only and return to pre-specified location in the
* compiled code to resume execution. This is mainly used as debugging
* feature to bypass problematic opcode implementations without
* disturbing the trace formation.
* 5) dvmJitToTraceSelect: Similar to dvmJitToInterpNormal except for the
* profiling operation. If the new Dalvik PC is dominated by an already
* translated trace, directly request a new translation if the destinaion
* trace doesn't exist.
* 6) dvmJitToBackwardBranch: special case for SELF_VERIFICATION when the
* destination Dalvik PC is included by the trace itself.
*/
struct JitToInterpEntries {
void (*dvmJitToInterpNormal)(void);
void (*dvmJitToInterpNoChain)(void);
void (*dvmJitToInterpPunt)(void);
void (*dvmJitToInterpSingleStep)(void);
void (*dvmJitToInterpTraceSelect)(void);
#if defined(WITH_SELF_VERIFICATION)
void (*dvmJitToInterpBackwardBranch)(void);
#else
void (*unused)(void); // Keep structure size constant
#endif
};
/* States of the interpreter when serving a JIT-related request */
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
kJitDone = 6, // No further JIT actions for interpBreak
};
#if defined(WITH_SELF_VERIFICATION)
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
};
#endif
/* 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 MAX_JIT_RUN_LEN 64
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
};
/*
* Element of a Jit trace description. If the isCode bit is set, it describes
* a contiguous sequence of Dalvik byte codes.
*/
struct JitCodeDesc {
unsigned numInsts:8; // Number of Byte codes in run
unsigned runEnd:1; // Run ends with last byte code
JitHint hint:7; // Hint to apply to final code of run
u2 startOffset; // Starting offset for trace run
};
/*
* A complete list of trace runs passed to the compiler looks like the
* following:
* frag1
* frag2
* frag3
* meta1
* :
* metan
* frag4
*
* frags 1-4 have the "isCode" field set and describe the location/length of
* real code traces, while metas 1-n are misc information.
* 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
* descriptor/loader of "this" and the currently resolved method pointer are
* three instances of meta information stored there.
*/
struct JitTraceRun {
union {
JitCodeDesc frag;
void* meta;
} info;
u4 isCode:1;
u4 unused:31;
};
#endif
#endif // DALVIK_INTERP_STATE_H_