OSDN Git Service

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