OSDN Git Service

am cf4e8b02: Merge "This is a contribution of x86-atom targeted assembly for the...
[android-x86/dalvik.git] / vm / analysis / DexVerify.c
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 /*
18  * Dalvik classfile verification.  This file contains the verifier entry
19  * points and the static constraint checks.
20  */
21 #include "Dalvik.h"
22 #include "analysis/CodeVerify.h"
23
24
25 /* fwd */
26 static bool verifyMethod(Method* meth, int verifyFlags);
27 static bool verifyInstructions(const Method* meth, InsnFlags* insnFlags,
28     int verifyFlags);
29
30
31 /*
32  * Initialize some things we need for verification.
33  */
34 bool dvmVerificationStartup(void)
35 {
36     gDvm.instrWidth = dexCreateInstrWidthTable();
37     gDvm.instrFormat = dexCreateInstrFormatTable();
38     gDvm.instrFlags = dexCreateInstrFlagsTable();
39     if (gDvm.instrWidth == NULL || gDvm.instrFormat == NULL ||
40         gDvm.instrFlags == NULL)
41     {
42         LOGE("Unable to create instruction tables\n");
43         return false;
44     }
45
46     return true;
47 }
48
49 /*
50  * Free up some things we needed for verification.
51  */
52 void dvmVerificationShutdown(void)
53 {
54     free(gDvm.instrWidth);
55     free(gDvm.instrFormat);
56     free(gDvm.instrFlags);
57 }
58
59 /*
60  * Induce verification on all classes loaded from this DEX file as part
61  * of pre-verification and optimization.  This is never called from a
62  * normally running VM.
63  *
64  * Returns "true" when all classes have been processed.
65  */
66 bool dvmVerifyAllClasses(DexFile* pDexFile)
67 {
68     u4 count = pDexFile->pHeader->classDefsSize;
69     u4 idx;
70
71     assert(gDvm.optimizing);
72
73     if (gDvm.classVerifyMode == VERIFY_MODE_NONE) {
74         LOGV("+++ verification is disabled, skipping all classes\n");
75         return true;
76     }
77     if (gDvm.classVerifyMode == VERIFY_MODE_REMOTE &&
78         gDvm.optimizingBootstrapClass)
79     {
80         LOGV("+++ verification disabled for bootstrap classes\n");
81         return true;
82     }
83
84     for (idx = 0; idx < count; idx++) {
85         const DexClassDef* pClassDef;
86         const char* classDescriptor;
87         ClassObject* clazz;
88
89         pClassDef = dexGetClassDef(pDexFile, idx);
90         classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
91
92         /* all classes are loaded into the bootstrap class loader */
93         clazz = dvmLookupClass(classDescriptor, NULL, false);
94         if (clazz != NULL) {
95             if (clazz->pDvmDex->pDexFile != pDexFile) {
96                 LOGD("DexOpt: not verifying '%s': multiple definitions\n",
97                     classDescriptor);
98             } else {
99                 if (dvmVerifyClass(clazz, VERIFY_DEFAULT)) {
100                     assert((clazz->accessFlags & JAVA_FLAGS_MASK) ==
101                         pClassDef->accessFlags);
102                     ((DexClassDef*)pClassDef)->accessFlags |=
103                         CLASS_ISPREVERIFIED;
104                 }
105                 /* keep going even if one fails */
106             }
107         } else {
108             LOGV("DexOpt: +++  not verifying '%s'\n", classDescriptor);
109         }
110     }
111
112     return true;
113 }
114
115 /*
116  * Verify a class.
117  *
118  * By the time we get here, the value of gDvm.classVerifyMode should already
119  * have been factored in.  If you want to call into the verifier even
120  * though verification is disabled, that's your business.
121  *
122  * Returns "true" on success.
123  */
124 bool dvmVerifyClass(ClassObject* clazz, int verifyFlags)
125 {
126     int i;
127
128     if (dvmIsClassVerified(clazz)) {
129         LOGD("Ignoring duplicate verify attempt on %s\n", clazz->descriptor);
130         return true;
131     }
132
133     //LOGI("Verify1 '%s'\n", clazz->descriptor);
134
135     // TODO - verify class structure in DEX?
136
137     for (i = 0; i < clazz->directMethodCount; i++) {
138         if (!verifyMethod(&clazz->directMethods[i], verifyFlags)) {
139             LOG_VFY("Verifier rejected class %s\n", clazz->descriptor);
140             return false;
141         }
142     }
143     for (i = 0; i < clazz->virtualMethodCount; i++) {
144         if (!verifyMethod(&clazz->virtualMethods[i], verifyFlags)) {
145             LOG_VFY("Verifier rejected class %s\n", clazz->descriptor);
146             return false;
147         }
148     }
149
150     return true;
151 }
152
153 /*
154  * Temporarily "undo" any breakpoints found in this method.  There is no risk
155  * of confusing the interpreter, because unverified code cannot be executed.
156  *
157  * Breakpoints can be set after a class is loaded but before it has been
158  * verified.
159  *
160  * The "breakpoint" opcode can replace any other opcode, leaving no
161  * indication of the original instruction's width or purpose in the
162  * instruction stream.  We either have to quietly undo the breakpoints
163  * before verification, or look up the original opcode whenever we need it.
164  * The latter is more efficient since we only slow down on code that
165  * actually has breakpoints, but it requires explicit handling in every
166  * function that examines the instruction stream.
167  *
168  * We need to ensure that the debugger doesn't insert any additional
169  * breakpoints while we work.  This either requires holding a lock on the
170  * breakpoint set throughout the verification of this method, or adding a
171  * "do not touch anything on these pages" list to the set.  Either way,
172  * the caller of this method must ensure that it calls "redo" to release
173  * state.
174  *
175  * A debugger could connect while we work, so we return without doing
176  * anything if a debugger doesn't happen to be connected now.  We can only
177  * avoid doing work if the debugger thread isn't running (dexopt, zygote,
178  * or debugging not configured).
179  *
180  * Returns "false" if we did nothing, "true" if we did stuff (and, hence,
181  * need to call "redo" at some point).
182  */
183 static bool undoBreakpoints(Method* meth)
184 {
185 #ifdef WITH_DEBUGGER
186     if (gDvm.optimizing || gDvm.zygote || !gDvm.jdwpConfigured)
187         return false;
188     dvmUndoBreakpoints(meth);
189     return true;
190 #else
191     return false;
192 #endif
193 }
194
195 /*
196  * Restore any breakpoints we undid previously.  Also has to update the
197  * stored "original opcode" value for any instruction that we replaced
198  * with a throw-verification-error op.
199  */
200 static void redoBreakpoints(Method* meth)
201 {
202 #ifdef WITH_DEBUGGER
203     if (gDvm.optimizing || gDvm.zygote || !gDvm.jdwpConfigured) {
204         /* should not be here */
205         assert(false);
206         return;
207     }
208     dvmRedoBreakpoints(meth);
209 #else
210     assert(false);
211 #endif
212 }
213
214 /*
215  * Perform verification on a single method.
216  *
217  * We do this in three passes:
218  *  (1) Walk through all code units, determining instruction lengths.
219  *  (2) Do static checks, including branch target and operand validation.
220  *  (3) Do structural checks, including data-flow analysis.
221  *
222  * Some checks may be bypassed depending on the verification mode.  We can't
223  * turn this stuff off completely if we want to do "exact" GC.
224  *
225  * - operands of getfield, putfield, getstatic, putstatic must be valid
226  * - operands of method invocation instructions must be valid
227  *
228  * - code array must not be empty
229  * - (N/A) code_length must be less than 65536
230  * - opcode of first instruction begins at index 0
231  * - only documented instructions may appear
232  * - each instruction follows the last
233  * - (below) last byte of last instruction is at (code_length-1)
234  */
235 static bool verifyMethod(Method* meth, int verifyFlags)
236 {
237     bool result = false;
238     UninitInstanceMap* uninitMap = NULL;
239     InsnFlags* insnFlags = NULL;
240     int i, newInstanceCount;
241     bool undidBreakpoints;
242
243     undidBreakpoints = undoBreakpoints(meth);
244
245     /*
246      * If there aren't any instructions, make sure that's expected, then
247      * exit successfully. Note: meth->insns gets set to a native function
248      * pointer on first call.
249      */
250     if (dvmGetMethodInsnsSize(meth) == 0) {
251         if (!dvmIsNativeMethod(meth) && !dvmIsAbstractMethod(meth)) {
252             LOG_VFY_METH(meth,
253                 "VFY: zero-length code in concrete non-native method\n");
254             goto bail;
255         }
256
257         goto success;
258     }
259
260     /*
261      * Sanity-check the register counts.  ins + locals = registers, so make
262      * sure that ins <= registers.
263      */
264     if (meth->insSize > meth->registersSize) {
265         LOG_VFY_METH(meth, "VFY: bad register counts (ins=%d regs=%d)\n",
266             meth->insSize, meth->registersSize);
267         goto bail;
268     }
269
270     /*
271      * Allocate and populate an array to hold instruction data.
272      *
273      * TODO: Consider keeping a reusable pre-allocated array sitting
274      * around for smaller methods.
275      */
276     insnFlags = (InsnFlags*)
277         calloc(dvmGetMethodInsnsSize(meth), sizeof(InsnFlags));
278     if (insnFlags == NULL)
279         goto bail;
280
281     /*
282      * Compute the width of each instruction and store the result in insnFlags.
283      * Count up the #of occurrences of new-instance instructions while we're
284      * at it.
285      */
286     if (!dvmComputeCodeWidths(meth, insnFlags, &newInstanceCount))
287         goto bail;
288
289     /*
290      * Allocate a map to hold the classes of uninitialized instances.
291      */
292     uninitMap = dvmCreateUninitInstanceMap(meth, insnFlags, newInstanceCount);
293     if (uninitMap == NULL)
294         goto bail;
295
296     /*
297      * Set the "in try" flags for all instructions guarded by a "try" block.
298      */
299     if (!dvmSetTryFlags(meth, insnFlags))
300         goto bail;
301
302     /*
303      * Perform static instruction verification.
304      */
305     if (!verifyInstructions(meth, insnFlags, verifyFlags))
306         goto bail;
307
308     /*
309      * Do code-flow analysis.  Do this after verifying the branch targets
310      * so we don't need to worry about it here.
311      *
312      * If there are no registers, we don't need to do much in the way of
313      * analysis, but we still need to verify that nothing actually tries
314      * to use a register.
315      */
316     if (!dvmVerifyCodeFlow(meth, insnFlags, uninitMap)) {
317         //LOGD("+++ %s failed code flow\n", meth->name);
318         goto bail;
319     }
320
321 success:
322     result = true;
323
324 bail:
325     if (undidBreakpoints)
326         redoBreakpoints(meth);
327     dvmFreeUninitInstanceMap(uninitMap);
328     free(insnFlags);
329     return result;
330 }
331
332
333 /*
334  * Verify an array data table.  "curOffset" is the offset of the fill-array-data
335  * instruction.
336  */
337 static bool checkArrayData(const Method* meth, int curOffset)
338 {
339     const int insnCount = dvmGetMethodInsnsSize(meth);
340     const u2* insns = meth->insns + curOffset;
341     const u2* arrayData;
342     int valueCount, valueWidth, tableSize;
343     int offsetToArrayData;
344
345     assert(curOffset >= 0 && curOffset < insnCount);
346
347     /* make sure the start of the array data table is in range */
348     offsetToArrayData = insns[1] | (((s4)insns[2]) << 16);
349     if (curOffset + offsetToArrayData < 0 ||
350         curOffset + offsetToArrayData + 2 >= insnCount)
351     {
352         LOG_VFY_METH(meth,
353             "VFY: invalid array data start: at %d, data offset %d, count %d\n",
354             curOffset, offsetToArrayData, insnCount);
355         return false;
356     }
357
358     /* offset to array data table is a relative branch-style offset */
359     arrayData = insns + offsetToArrayData;
360
361     /* make sure the table is 32-bit aligned */
362     if ((((u4) arrayData) & 0x03) != 0) {
363         LOG_VFY_METH(meth,
364             "VFY: unaligned array data table: at %d, data offset %d\n",
365             curOffset, offsetToArrayData);
366         return false;
367     }
368
369     valueWidth = arrayData[1];
370     valueCount = *(u4*)(&arrayData[2]);
371
372     tableSize = 4 + (valueWidth * valueCount + 1) / 2;
373
374     /* make sure the end of the switch is in range */
375     if (curOffset + offsetToArrayData + tableSize > insnCount) {
376         LOG_VFY_METH(meth,
377             "VFY: invalid array data end: at %d, data offset %d, end %d, "
378             "count %d\n",
379             curOffset, offsetToArrayData, 
380             curOffset + offsetToArrayData + tableSize,
381             insnCount);
382         return false;
383     }
384
385     return true;
386 }
387
388
389 /*
390  * Decode the current instruction.
391  */
392 static void decodeInstruction(const Method* meth, int insnIdx,
393     DecodedInstruction* pDecInsn)
394 {
395     dexDecodeInstruction(gDvm.instrFormat, meth->insns + insnIdx, pDecInsn);
396 }
397
398
399 /*
400  * Perform static checks on a "new-instance" instruction.  Specifically,
401  * make sure the class reference isn't for an array class.
402  *
403  * We don't need the actual class, just a pointer to the class name.
404  */
405 static bool checkNewInstance(const Method* meth, int insnIdx)
406 {
407     DvmDex* pDvmDex = meth->clazz->pDvmDex;
408     DecodedInstruction decInsn;
409     const char* classDescriptor;
410     u4 idx;
411
412     decodeInstruction(meth, insnIdx, &decInsn);
413     idx = decInsn.vB;       // 2nd item
414     if (idx >= pDvmDex->pHeader->typeIdsSize) {
415         LOG_VFY_METH(meth, "VFY: bad type index %d (max %d)\n",
416             idx, pDvmDex->pHeader->typeIdsSize);
417         return false;
418     }
419
420     classDescriptor = dexStringByTypeIdx(pDvmDex->pDexFile, idx);
421     if (classDescriptor[0] != 'L') {
422         LOG_VFY_METH(meth, "VFY: can't call new-instance on type '%s'\n",
423             classDescriptor);
424         return false;
425     }
426
427     return true;
428 }
429
430 /*
431  * Perform static checks on a "new-array" instruction.  Specifically, make
432  * sure they aren't creating an array of arrays that causes the number of
433  * dimensions to exceed 255.
434  */
435 static bool checkNewArray(const Method* meth, int insnIdx)
436 {
437     DvmDex* pDvmDex = meth->clazz->pDvmDex;
438     DecodedInstruction decInsn;
439     const char* classDescriptor;
440     u4 idx;
441
442     decodeInstruction(meth, insnIdx, &decInsn);
443     idx = decInsn.vC;       // 3rd item
444     if (idx >= pDvmDex->pHeader->typeIdsSize) {
445         LOG_VFY_METH(meth, "VFY: bad type index %d (max %d)\n",
446             idx, pDvmDex->pHeader->typeIdsSize);
447         return false;
448     }
449
450     classDescriptor = dexStringByTypeIdx(pDvmDex->pDexFile, idx);
451
452     int bracketCount = 0;
453     const char* cp = classDescriptor;
454     while (*cp++ == '[')
455         bracketCount++;
456
457     if (bracketCount == 0) {
458         /* The given class must be an array type. */
459         LOG_VFY_METH(meth, "VFY: can't new-array class '%s' (not an array)\n",
460             classDescriptor);
461         return false;
462     } else if (bracketCount > 255) {
463         /* It is illegal to create an array of more than 255 dimensions. */
464         LOG_VFY_METH(meth, "VFY: can't new-array class '%s' (exceeds limit)\n",
465             classDescriptor);
466         return false;
467     }
468
469     return true;
470 }
471
472 /*
473  * Perform static checks on an instruction that takes a class constant.
474  * Ensure that the class index is in the valid range.
475  */
476 static bool checkTypeIndex(const Method* meth, int insnIdx, bool useB)
477 {
478     DvmDex* pDvmDex = meth->clazz->pDvmDex;
479     DecodedInstruction decInsn;
480     u4 idx;
481
482     decodeInstruction(meth, insnIdx, &decInsn);
483     if (useB)
484         idx = decInsn.vB;
485     else
486         idx = decInsn.vC;
487     if (idx >= pDvmDex->pHeader->typeIdsSize) {
488         LOG_VFY_METH(meth, "VFY: bad type index %d (max %d)\n",
489             idx, pDvmDex->pHeader->typeIdsSize);
490         return false;
491     }
492
493     return true;
494 }
495
496 /*
497  * Perform static checks on a field get or set instruction.  All we do
498  * here is ensure that the field index is in the valid range.
499  */
500 static bool checkFieldIndex(const Method* meth, int insnIdx, bool useB)
501 {
502     DvmDex* pDvmDex = meth->clazz->pDvmDex;
503     DecodedInstruction decInsn;
504     u4 idx;
505
506     decodeInstruction(meth, insnIdx, &decInsn);
507     if (useB)
508         idx = decInsn.vB;
509     else
510         idx = decInsn.vC;
511     if (idx >= pDvmDex->pHeader->fieldIdsSize) {
512         LOG_VFY_METH(meth,
513             "VFY: bad field index %d (max %d) at offset 0x%04x\n",
514             idx, pDvmDex->pHeader->fieldIdsSize, insnIdx);
515         return false;
516     }
517
518     return true;
519 }
520
521 /*
522  * Perform static checks on a method invocation instruction.  All we do
523  * here is ensure that the method index is in the valid range.
524  */
525 static bool checkMethodIndex(const Method* meth, int insnIdx)
526 {
527     DvmDex* pDvmDex = meth->clazz->pDvmDex;
528     DecodedInstruction decInsn;
529
530     decodeInstruction(meth, insnIdx, &decInsn);
531     if (decInsn.vB >= pDvmDex->pHeader->methodIdsSize) {
532         LOG_VFY_METH(meth, "VFY: bad method index %d (max %d)\n",
533             decInsn.vB, pDvmDex->pHeader->methodIdsSize);
534         return false;
535     }
536
537     return true;
538 }
539
540 /*
541  * Perform static checks on a string constant instruction.  All we do
542  * here is ensure that the string index is in the valid range.
543  */
544 static bool checkStringIndex(const Method* meth, int insnIdx)
545 {
546     DvmDex* pDvmDex = meth->clazz->pDvmDex;
547     DecodedInstruction decInsn;
548
549     decodeInstruction(meth, insnIdx, &decInsn);
550     if (decInsn.vB >= pDvmDex->pHeader->stringIdsSize) {
551         LOG_VFY_METH(meth, "VFY: bad string index %d (max %d)\n",
552             decInsn.vB, pDvmDex->pHeader->stringIdsSize);
553         return false;
554     }
555
556     return true;
557 }
558
559 /*
560  * Perform static verification on instructions.
561  *
562  * As a side effect, this sets the "branch target" flags in InsnFlags.
563  *
564  * "(CF)" items are handled during code-flow analysis.
565  *
566  * v3 4.10.1
567  * - target of each jump and branch instruction must be valid
568  * - targets of switch statements must be valid
569  * - (CF) operands referencing constant pool entries must be valid
570  * - (CF) operands of getfield, putfield, getstatic, putstatic must be valid
571  * - (new) verify operands of "quick" field ops
572  * - (CF) operands of method invocation instructions must be valid
573  * - (new) verify operands of "quick" method invoke ops
574  * - (CF) only invoke-direct can call a method starting with '<'
575  * - (CF) <clinit> must never be called explicitly
576  * - (CF) operands of instanceof, checkcast, new (and variants) must be valid
577  * - new-array[-type] limited to 255 dimensions
578  * - can't use "new" on an array class
579  * - (?) limit dimensions in multi-array creation
580  * - (CF) local variable load/store register values must be in valid range
581  *
582  * v3 4.11.1.2
583  * - branches must be within the bounds of the code array
584  * - targets of all control-flow instructions are the start of an instruction
585  * - (CF) register accesses fall within range of allocated registers
586  * - (N/A) access to constant pool must be of appropriate type
587  * - (CF) code does not end in the middle of an instruction
588  * - (CF) execution cannot fall off the end of the code
589  * - (earlier) for each exception handler, the "try" area must begin and
590  *   end at the start of an instruction (end can be at the end of the code)
591  * - (earlier) for each exception handler, the handler must start at a valid
592  *   instruction
593  *
594  * TODO: move some of the "CF" items in here for better performance (the
595  * code-flow analysis sometimes has to process the same instruction several
596  * times).
597  */
598 static bool verifyInstructions(const Method* meth, InsnFlags* insnFlags,
599     int verifyFlags)
600 {
601     const int insnCount = dvmGetMethodInsnsSize(meth);
602     const u2* insns = meth->insns;
603     int i;
604
605     /* the start of the method is a "branch target" */
606     dvmInsnSetBranchTarget(insnFlags, 0, true);
607
608     for (i = 0; i < insnCount; /**/) {
609         /*
610          * These types of instructions can be GC points.  To support precise
611          * GC, all such instructions must export the PC in the interpreter,
612          * or the GC won't be able to identify the current PC for the thread.
613          */
614         static const int gcMask = kInstrCanBranch | kInstrCanSwitch |
615             kInstrCanThrow | kInstrCanReturn;
616
617         int width = dvmInsnGetWidth(insnFlags, i);
618         OpCode opcode = *insns & 0xff;
619         InstructionFlags opFlags = dexGetInstrFlags(gDvm.instrFlags, opcode);
620         int offset, absOffset;
621
622         if ((opFlags & gcMask) != 0) {
623             /*
624              * This instruction is probably a GC point.  Branch instructions
625              * only qualify if they go backward, so we need to check the
626              * offset.
627              */
628             int offset = -1;
629             bool unused;
630             if (dvmGetBranchTarget(meth, insnFlags, i, &offset, &unused)) {
631                 if (offset < 0) {
632                     dvmInsnSetGcPoint(insnFlags, i, true);
633                 }
634             } else {
635                 /* not a branch target */
636                 dvmInsnSetGcPoint(insnFlags, i, true);
637             }
638         }
639
640         switch (opcode) {
641         case OP_NOP:
642             /* plain no-op or switch table data; nothing to do here */
643             break;
644
645         case OP_CONST_STRING:
646         case OP_CONST_STRING_JUMBO:
647             if (!checkStringIndex(meth, i))
648                 return false;
649             break;
650
651         case OP_CONST_CLASS:
652         case OP_CHECK_CAST:
653             if (!checkTypeIndex(meth, i, true))
654                 return false;
655             break;
656         case OP_INSTANCE_OF:
657             if (!checkTypeIndex(meth, i, false))
658                 return false;
659             break;
660
661         case OP_PACKED_SWITCH:
662         case OP_SPARSE_SWITCH:
663             /* verify the associated table */
664             if (!dvmCheckSwitchTargets(meth, insnFlags, i))
665                 return false;
666             break;
667
668         case OP_FILL_ARRAY_DATA:
669             /* verify the associated table */
670             if (!checkArrayData(meth, i))
671                 return false;
672             break;
673
674         case OP_GOTO:
675         case OP_GOTO_16:
676         case OP_IF_EQ:
677         case OP_IF_NE:
678         case OP_IF_LT:
679         case OP_IF_GE:
680         case OP_IF_GT:
681         case OP_IF_LE:
682         case OP_IF_EQZ:
683         case OP_IF_NEZ:
684         case OP_IF_LTZ:
685         case OP_IF_GEZ:
686         case OP_IF_GTZ:
687         case OP_IF_LEZ:
688             /* check the destination */
689             if (!dvmCheckBranchTarget(meth, insnFlags, i, false))
690                 return false;
691             break;
692         case OP_GOTO_32:
693             /* check the destination; self-branch is okay */
694             if (!dvmCheckBranchTarget(meth, insnFlags, i, true))
695                 return false;
696             break;
697
698         case OP_NEW_INSTANCE:
699             if (!checkNewInstance(meth, i))
700                 return false;
701             break;
702
703         case OP_NEW_ARRAY:
704             if (!checkNewArray(meth, i))
705                 return false;
706             break;
707
708         case OP_FILLED_NEW_ARRAY:
709             if (!checkTypeIndex(meth, i, true))
710                 return false;
711             break;
712         case OP_FILLED_NEW_ARRAY_RANGE:
713             if (!checkTypeIndex(meth, i, true))
714                 return false;
715             break;
716
717         case OP_IGET:
718         case OP_IGET_WIDE:
719         case OP_IGET_OBJECT:
720         case OP_IGET_BOOLEAN:
721         case OP_IGET_BYTE:
722         case OP_IGET_CHAR:
723         case OP_IGET_SHORT:
724         case OP_IPUT:
725         case OP_IPUT_WIDE:
726         case OP_IPUT_OBJECT:
727         case OP_IPUT_BOOLEAN:
728         case OP_IPUT_BYTE:
729         case OP_IPUT_CHAR:
730         case OP_IPUT_SHORT:
731             /* check the field index */
732             if (!checkFieldIndex(meth, i, false))
733                 return false;
734             break;
735         case OP_SGET:
736         case OP_SGET_WIDE:
737         case OP_SGET_OBJECT:
738         case OP_SGET_BOOLEAN:
739         case OP_SGET_BYTE:
740         case OP_SGET_CHAR:
741         case OP_SGET_SHORT:
742         case OP_SPUT:
743         case OP_SPUT_WIDE:
744         case OP_SPUT_OBJECT:
745         case OP_SPUT_BOOLEAN:
746         case OP_SPUT_BYTE:
747         case OP_SPUT_CHAR:
748         case OP_SPUT_SHORT:
749             /* check the field index */
750             if (!checkFieldIndex(meth, i, true))
751                 return false;
752             break;
753
754         case OP_INVOKE_VIRTUAL:
755         case OP_INVOKE_SUPER:
756         case OP_INVOKE_DIRECT:
757         case OP_INVOKE_STATIC:
758         case OP_INVOKE_INTERFACE:
759         case OP_INVOKE_VIRTUAL_RANGE:
760         case OP_INVOKE_SUPER_RANGE:
761         case OP_INVOKE_DIRECT_RANGE:
762         case OP_INVOKE_STATIC_RANGE:
763         case OP_INVOKE_INTERFACE_RANGE:
764             /* check the method index */
765             if (!checkMethodIndex(meth, i))
766                 return false;
767             break;
768
769         case OP_EXECUTE_INLINE:
770         case OP_INVOKE_DIRECT_EMPTY:
771         case OP_IGET_QUICK:
772         case OP_IGET_WIDE_QUICK:
773         case OP_IGET_OBJECT_QUICK:
774         case OP_IPUT_QUICK:
775         case OP_IPUT_WIDE_QUICK:
776         case OP_IPUT_OBJECT_QUICK:
777         case OP_INVOKE_VIRTUAL_QUICK:
778         case OP_INVOKE_VIRTUAL_QUICK_RANGE:
779         case OP_INVOKE_SUPER_QUICK:
780         case OP_INVOKE_SUPER_QUICK_RANGE:
781             if ((verifyFlags & VERIFY_ALLOW_OPT_INSTRS) == 0) {
782                 LOG_VFY("VFY: not expecting optimized instructions\n");
783                 return false;
784             }
785             break;
786
787         default:
788             /* nothing to do */
789             break;
790         }
791
792         assert(width > 0);
793         i += width;
794         insns += width;
795     }
796
797     /* make sure the last instruction ends at the end of the insn area */
798     if (i != insnCount) {
799         LOG_VFY_METH(meth,
800             "VFY: code did not end when expected (end at %d, count %d)\n",
801             i, insnCount);
802         return false;
803     }
804
805     return true;
806 }
807