• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 /* common includes */
18 #include "Dalvik.h"
19 #include "interp/InterpDefs.h"
20 #include "mterp/Mterp.h"
21 #include <math.h>                   // needed for fmod, fmodf
22 
23 /*
24  * Configuration defines.  These affect the C implementations, i.e. the
25  * portable interpreter(s) and C stubs.
26  *
27  * Some defines are controlled by the Makefile, e.g.:
28  *   WITH_PROFILER
29  *   WITH_DEBUGGER
30  *   WITH_INSTR_CHECKS
31  *   WITH_TRACKREF_CHECKS
32  *   EASY_GDB
33  *   NDEBUG
34  *
35  * If THREADED_INTERP is not defined, we use a classic "while true / switch"
36  * interpreter.  If it is defined, then the tail end of each instruction
37  * handler fetches the next instruction and jumps directly to the handler.
38  * This increases the size of the "Std" interpreter by about 10%, but
39  * provides a speedup of about the same magnitude.
40  *
41  * There's a "hybrid" approach that uses a goto table instead of a switch
42  * statement, avoiding the "is the opcode in range" tests required for switch.
43  * The performance is close to the threaded version, and without the 10%
44  * size increase, but the benchmark results are off enough that it's not
45  * worth adding as a third option.
46  */
47 #define THREADED_INTERP             /* threaded vs. while-loop interpreter */
48 
49 #ifdef WITH_INSTR_CHECKS            /* instruction-level paranoia */
50 # define CHECK_BRANCH_OFFSETS
51 # define CHECK_REGISTER_INDICES
52 #endif
53 
54 /*
55  * ARM EABI requires 64-bit alignment for access to 64-bit data types.  We
56  * can't just use pointers to copy 64-bit values out of our interpreted
57  * register set, because gcc will generate ldrd/strd.
58  *
59  * The __UNION version copies data in and out of a union.  The __MEMCPY
60  * version uses a memcpy() call to do the transfer; gcc is smart enough to
61  * not actually call memcpy().  The __UNION version is very bad on ARM;
62  * it only uses one more instruction than __MEMCPY, but for some reason
63  * gcc thinks it needs separate storage for every instance of the union.
64  * On top of that, it feels the need to zero them out at the start of the
65  * method.  Net result is we zero out ~700 bytes of stack space at the top
66  * of the interpreter using ARM STM instructions.
67  */
68 #if defined(__ARM_EABI__)
69 //# define NO_UNALIGN_64__UNION
70 # define NO_UNALIGN_64__MEMCPY
71 #endif
72 
73 //#define LOG_INSTR                   /* verbose debugging */
74 /* set and adjust ANDROID_LOG_TAGS='*:i jdwp:i dalvikvm:i dalvikvmi:i' */
75 
76 /*
77  * Keep a tally of accesses to fields.  Currently only works if full DEX
78  * optimization is disabled.
79  */
80 #ifdef PROFILE_FIELD_ACCESS
81 # define UPDATE_FIELD_GET(_field) { (_field)->gets++; }
82 # define UPDATE_FIELD_PUT(_field) { (_field)->puts++; }
83 #else
84 # define UPDATE_FIELD_GET(_field) ((void)0)
85 # define UPDATE_FIELD_PUT(_field) ((void)0)
86 #endif
87 
88 /*
89  * Adjust the program counter.  "_offset" is a signed int, in 16-bit units.
90  *
91  * Assumes the existence of "const u2* pc" and "const u2* curMethod->insns".
92  *
93  * We don't advance the program counter until we finish an instruction or
94  * branch, because we do want to have to unroll the PC if there's an
95  * exception.
96  */
97 #ifdef CHECK_BRANCH_OFFSETS
98 # define ADJUST_PC(_offset) do {                                            \
99         int myoff = _offset;        /* deref only once */                   \
100         if (pc + myoff < curMethod->insns ||                                \
101             pc + myoff >= curMethod->insns + dvmGetMethodInsnsSize(curMethod)) \
102         {                                                                   \
103             char* desc;                                                     \
104             desc = dexProtoCopyMethodDescriptor(&curMethod->prototype);     \
105             LOGE("Invalid branch %d at 0x%04x in %s.%s %s\n",               \
106                 myoff, (int) (pc - curMethod->insns),                       \
107                 curMethod->clazz->descriptor, curMethod->name, desc);       \
108             free(desc);                                                     \
109             dvmAbort();                                                     \
110         }                                                                   \
111         pc += myoff;                                                        \
112     } while (false)
113 #else
114 # define ADJUST_PC(_offset) (pc += _offset)
115 #endif
116 
117 /*
118  * If enabled, log instructions as we execute them.
119  */
120 #ifdef LOG_INSTR
121 # define ILOGD(...) ILOG(LOG_DEBUG, __VA_ARGS__)
122 # define ILOGV(...) ILOG(LOG_VERBOSE, __VA_ARGS__)
123 # define ILOG(_level, ...) do {                                             \
124         char debugStrBuf[128];                                              \
125         snprintf(debugStrBuf, sizeof(debugStrBuf), __VA_ARGS__);            \
126         if (curMethod != NULL)                                                 \
127             LOG(_level, LOG_TAG"i", "%-2d|%04x%s\n",                        \
128                 self->threadId, (int)(pc - curMethod->insns), debugStrBuf); \
129         else                                                                \
130             LOG(_level, LOG_TAG"i", "%-2d|####%s\n",                        \
131                 self->threadId, debugStrBuf);                               \
132     } while(false)
133 void dvmDumpRegs(const Method* method, const u4* framePtr, bool inOnly);
134 # define DUMP_REGS(_meth, _frame, _inOnly) dvmDumpRegs(_meth, _frame, _inOnly)
135 static const char kSpacing[] = "            ";
136 #else
137 # define ILOGD(...) ((void)0)
138 # define ILOGV(...) ((void)0)
139 # define DUMP_REGS(_meth, _frame, _inOnly) ((void)0)
140 #endif
141 
142 /* get a long from an array of u4 */
getLongFromArray(const u4 * ptr,int idx)143 static inline s8 getLongFromArray(const u4* ptr, int idx)
144 {
145 #if defined(NO_UNALIGN_64__UNION)
146     union { s8 ll; u4 parts[2]; } conv;
147 
148     ptr += idx;
149     conv.parts[0] = ptr[0];
150     conv.parts[1] = ptr[1];
151     return conv.ll;
152 #elif defined(NO_UNALIGN_64__MEMCPY)
153     s8 val;
154     memcpy(&val, &ptr[idx], 8);
155     return val;
156 #else
157     return *((s8*) &ptr[idx]);
158 #endif
159 }
160 
161 /* store a long into an array of u4 */
putLongToArray(u4 * ptr,int idx,s8 val)162 static inline void putLongToArray(u4* ptr, int idx, s8 val)
163 {
164 #if defined(NO_UNALIGN_64__UNION)
165     union { s8 ll; u4 parts[2]; } conv;
166 
167     ptr += idx;
168     conv.ll = val;
169     ptr[0] = conv.parts[0];
170     ptr[1] = conv.parts[1];
171 #elif defined(NO_UNALIGN_64__MEMCPY)
172     memcpy(&ptr[idx], &val, 8);
173 #else
174     *((s8*) &ptr[idx]) = val;
175 #endif
176 }
177 
178 /* get a double from an array of u4 */
getDoubleFromArray(const u4 * ptr,int idx)179 static inline double getDoubleFromArray(const u4* ptr, int idx)
180 {
181 #if defined(NO_UNALIGN_64__UNION)
182     union { double d; u4 parts[2]; } conv;
183 
184     ptr += idx;
185     conv.parts[0] = ptr[0];
186     conv.parts[1] = ptr[1];
187     return conv.d;
188 #elif defined(NO_UNALIGN_64__MEMCPY)
189     double dval;
190     memcpy(&dval, &ptr[idx], 8);
191     return dval;
192 #else
193     return *((double*) &ptr[idx]);
194 #endif
195 }
196 
197 /* store a double into an array of u4 */
putDoubleToArray(u4 * ptr,int idx,double dval)198 static inline void putDoubleToArray(u4* ptr, int idx, double dval)
199 {
200 #if defined(NO_UNALIGN_64__UNION)
201     union { double d; u4 parts[2]; } conv;
202 
203     ptr += idx;
204     conv.d = dval;
205     ptr[0] = conv.parts[0];
206     ptr[1] = conv.parts[1];
207 #elif defined(NO_UNALIGN_64__MEMCPY)
208     memcpy(&ptr[idx], &dval, 8);
209 #else
210     *((double*) &ptr[idx]) = dval;
211 #endif
212 }
213 
214 /*
215  * If enabled, validate the register number on every access.  Otherwise,
216  * just do an array access.
217  *
218  * Assumes the existence of "u4* fp".
219  *
220  * "_idx" may be referenced more than once.
221  */
222 #ifdef CHECK_REGISTER_INDICES
223 # define GET_REGISTER(_idx) \
224     ( (_idx) < curMethod->registersSize ? \
225         (fp[(_idx)]) : (assert(!"bad reg"),1969) )
226 # define SET_REGISTER(_idx, _val) \
227     ( (_idx) < curMethod->registersSize ? \
228         (fp[(_idx)] = (u4)(_val)) : (assert(!"bad reg"),1969) )
229 # define GET_REGISTER_AS_OBJECT(_idx)       ((Object *)GET_REGISTER(_idx))
230 # define SET_REGISTER_AS_OBJECT(_idx, _val) SET_REGISTER(_idx, (s4)_val)
231 # define GET_REGISTER_INT(_idx) ((s4) GET_REGISTER(_idx))
232 # define SET_REGISTER_INT(_idx, _val) SET_REGISTER(_idx, (s4)_val)
233 # define GET_REGISTER_WIDE(_idx) \
234     ( (_idx) < curMethod->registersSize-1 ? \
235         getLongFromArray(fp, (_idx)) : (assert(!"bad reg"),1969) )
236 # define SET_REGISTER_WIDE(_idx, _val) \
237     ( (_idx) < curMethod->registersSize-1 ? \
238         putLongToArray(fp, (_idx), (_val)) : (assert(!"bad reg"),1969) )
239 # define GET_REGISTER_FLOAT(_idx) \
240     ( (_idx) < curMethod->registersSize ? \
241         (*((float*) &fp[(_idx)])) : (assert(!"bad reg"),1969.0f) )
242 # define SET_REGISTER_FLOAT(_idx, _val) \
243     ( (_idx) < curMethod->registersSize ? \
244         (*((float*) &fp[(_idx)]) = (_val)) : (assert(!"bad reg"),1969.0f) )
245 # define GET_REGISTER_DOUBLE(_idx) \
246     ( (_idx) < curMethod->registersSize-1 ? \
247         getDoubleFromArray(fp, (_idx)) : (assert(!"bad reg"),1969.0) )
248 # define SET_REGISTER_DOUBLE(_idx, _val) \
249     ( (_idx) < curMethod->registersSize-1 ? \
250         putDoubleToArray(fp, (_idx), (_val)) : (assert(!"bad reg"),1969.0) )
251 #else
252 # define GET_REGISTER(_idx)                 (fp[(_idx)])
253 # define SET_REGISTER(_idx, _val)           (fp[(_idx)] = (_val))
254 # define GET_REGISTER_AS_OBJECT(_idx)       ((Object*) fp[(_idx)])
255 # define SET_REGISTER_AS_OBJECT(_idx, _val) (fp[(_idx)] = (u4)(_val))
256 # define GET_REGISTER_INT(_idx)             ((s4)GET_REGISTER(_idx))
257 # define SET_REGISTER_INT(_idx, _val)       SET_REGISTER(_idx, (s4)_val)
258 # define GET_REGISTER_WIDE(_idx)            getLongFromArray(fp, (_idx))
259 # define SET_REGISTER_WIDE(_idx, _val)      putLongToArray(fp, (_idx), (_val))
260 # define GET_REGISTER_FLOAT(_idx)           (*((float*) &fp[(_idx)]))
261 # define SET_REGISTER_FLOAT(_idx, _val)     (*((float*) &fp[(_idx)]) = (_val))
262 # define GET_REGISTER_DOUBLE(_idx)          getDoubleFromArray(fp, (_idx))
263 # define SET_REGISTER_DOUBLE(_idx, _val)    putDoubleToArray(fp, (_idx), (_val))
264 #endif
265 
266 /*
267  * Get 16 bits from the specified offset of the program counter.  We always
268  * want to load 16 bits at a time from the instruction stream -- it's more
269  * efficient than 8 and won't have the alignment problems that 32 might.
270  *
271  * Assumes existence of "const u2* pc".
272  */
273 #define FETCH(_offset)     (pc[(_offset)])
274 
275 /*
276  * Extract instruction byte from 16-bit fetch (_inst is a u2).
277  */
278 #define INST_INST(_inst)    ((_inst) & 0xff)
279 
280 /*
281  * Extract the "vA, vB" 4-bit registers from the instruction word (_inst is u2).
282  */
283 #define INST_A(_inst)       (((_inst) >> 8) & 0x0f)
284 #define INST_B(_inst)       ((_inst) >> 12)
285 
286 /*
287  * Get the 8-bit "vAA" 8-bit register index from the instruction word.
288  * (_inst is u2)
289  */
290 #define INST_AA(_inst)      ((_inst) >> 8)
291 
292 /*
293  * The current PC must be available to Throwable constructors, e.g.
294  * those created by dvmThrowException(), so that the exception stack
295  * trace can be generated correctly.  If we don't do this, the offset
296  * within the current method won't be shown correctly.  See the notes
297  * in Exception.c.
298  *
299  * Assumes existence of "u4* fp" and "const u2* pc".
300  */
301 #define EXPORT_PC()         (SAVEAREA_FROM_FP(fp)->xtra.currentPc = pc)
302 
303 /*
304  * Determine if we need to switch to a different interpreter.  "_current"
305  * is either INTERP_STD or INTERP_DBG.  It should be fixed for a given
306  * interpreter generation file, which should remove the outer conditional
307  * from the following.
308  *
309  * If we're building without debug and profiling support, we never switch.
310  */
311 #if defined(WITH_PROFILER) || defined(WITH_DEBUGGER)
312 # define NEED_INTERP_SWITCH(_current) (                                     \
313     (_current == INTERP_STD) ?                                              \
314         dvmDebuggerOrProfilerActive() : !dvmDebuggerOrProfilerActive() )
315 #else
316 # define NEED_INTERP_SWITCH(_current) (false)
317 #endif
318 
319 /*
320  * Look up an interface on a class using the cache.
321  */
dvmFindInterfaceMethodInCache(ClassObject * thisClass,u4 methodIdx,const Method * method,DvmDex * methodClassDex)322 INLINE Method* dvmFindInterfaceMethodInCache(ClassObject* thisClass,
323     u4 methodIdx, const Method* method, DvmDex* methodClassDex)
324 {
325 #define ATOMIC_CACHE_CALC \
326     dvmInterpFindInterfaceMethod(thisClass, methodIdx, method, methodClassDex)
327 
328     return (Method*) ATOMIC_CACHE_LOOKUP(methodClassDex->pInterfaceCache,
329                 DEX_INTERFACE_CACHE_SIZE, thisClass, methodIdx);
330 
331 #undef ATOMIC_CACHE_CALC
332 }
333 
334 /*
335  * Check to see if "obj" is NULL.  If so, throw an exception.  Assumes the
336  * pc has already been exported to the stack.
337  *
338  * Perform additional checks on debug builds.
339  *
340  * Use this to check for NULL when the instruction handler calls into
341  * something that could throw an exception (so we have already called
342  * EXPORT_PC at the top).
343  */
checkForNull(Object * obj)344 static inline bool checkForNull(Object* obj)
345 {
346     if (obj == NULL) {
347         dvmThrowException("Ljava/lang/NullPointerException;", NULL);
348         return false;
349     }
350 #ifdef WITH_EXTRA_OBJECT_VALIDATION
351     if (!dvmIsValidObject(obj)) {
352         LOGE("Invalid object %p\n", obj);
353         dvmAbort();
354     }
355 #endif
356 #ifndef NDEBUG
357     if (obj->clazz == NULL || ((u4) obj->clazz) <= 65536) {
358         /* probable heap corruption */
359         LOGE("Invalid object class %p (in %p)\n", obj->clazz, obj);
360         dvmAbort();
361     }
362 #endif
363     return true;
364 }
365 
366 /*
367  * Check to see if "obj" is NULL.  If so, export the PC into the stack
368  * frame and throw an exception.
369  *
370  * Perform additional checks on debug builds.
371  *
372  * Use this to check for NULL when the instruction handler doesn't do
373  * anything else that can throw an exception.
374  */
checkForNullExportPC(Object * obj,u4 * fp,const u2 * pc)375 static inline bool checkForNullExportPC(Object* obj, u4* fp, const u2* pc)
376 {
377     if (obj == NULL) {
378         EXPORT_PC();
379         dvmThrowException("Ljava/lang/NullPointerException;", NULL);
380         return false;
381     }
382 #ifdef WITH_EXTRA_OBJECT_VALIDATION
383     if (!dvmIsValidObject(obj)) {
384         LOGE("Invalid object %p\n", obj);
385         dvmAbort();
386     }
387 #endif
388 #ifndef NDEBUG
389     if (obj->clazz == NULL || ((u4) obj->clazz) <= 65536) {
390         /* probable heap corruption */
391         LOGE("Invalid object class %p (in %p)\n", obj->clazz, obj);
392         dvmAbort();
393     }
394 #endif
395     return true;
396 }
397 
398