Optimize.cpp revision 60fc806b679a3655c228b4093058c59941a49cfe
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 * Perform some simple bytecode optimizations, chiefly "quickening" of
19 * opcodes.
20 */
21#include "Dalvik.h"
22#include "libdex/InstrUtils.h"
23#include "Optimize.h"
24
25#include <zlib.h>
26
27#include <stdlib.h>
28
29/*
30 * Virtual/direct calls to "method" are replaced with an execute-inline
31 * instruction with index "idx".
32 */
33struct InlineSub {
34    Method* method;
35    int     inlineIdx;
36};
37
38
39/* fwd */
40static void optimizeMethod(Method* method, bool essentialOnly);
41static void rewriteInstField(Method* method, u2* insns, Opcode quickOpc,
42    Opcode volatileOpc);
43static void rewriteJumboInstField(Method* method, u2* insns,
44    Opcode volatileOpc);
45static void rewriteStaticField(Method* method, u2* insns, Opcode volatileOpc);
46static void rewriteJumboStaticField(Method* method, u2* insns,
47    Opcode volatileOpc);
48static void rewriteVirtualInvoke(Method* method, u2* insns, Opcode newOpc);
49static bool rewriteInvokeObjectInit(Method* method, u2* insns);
50static bool rewriteJumboInvokeObjectInit(Method* method, u2* insns);
51static bool rewriteExecuteInline(Method* method, u2* insns,
52    MethodType methodType);
53static bool rewriteExecuteInlineRange(Method* method, u2* insns,
54    MethodType methodType);
55static void rewriteReturnVoid(Method* method, u2* insns);
56static bool needsReturnBarrier(Method* method);
57
58
59/*
60 * Create a table of inline substitutions.  Sets gDvm.inlineSubs.
61 *
62 * TODO: this is currently just a linear array.  We will want to put this
63 * into a hash table as the list size increases.
64 */
65bool dvmCreateInlineSubsTable()
66{
67    const InlineOperation* ops = dvmGetInlineOpsTable();
68    const int count = dvmGetInlineOpsTableLength();
69    InlineSub* table;
70    int i, tableIndex;
71
72    assert(gDvm.inlineSubs == NULL);
73
74    /*
75     * One slot per entry, plus an end-of-list marker.
76     */
77    table = (InlineSub*) calloc(count + 1, sizeof(InlineSub));
78
79    tableIndex = 0;
80    for (i = 0; i < count; i++) {
81        Method* method = dvmFindInlinableMethod(ops[i].classDescriptor,
82            ops[i].methodName, ops[i].methodSignature);
83        if (method == NULL) {
84            /*
85             * Not expected.  We only use this for key methods in core
86             * classes, so we should always be able to find them.
87             */
88            LOGE("Unable to find method for inlining: %s.%s:%s",
89                ops[i].classDescriptor, ops[i].methodName,
90                ops[i].methodSignature);
91            return false;
92        }
93
94        table[tableIndex].method = method;
95        table[tableIndex].inlineIdx = i;
96        tableIndex++;
97    }
98
99    /* mark end of table */
100    table[tableIndex].method = NULL;
101
102    gDvm.inlineSubs = table;
103    return true;
104}
105
106/*
107 * Release inline sub data structure.
108 */
109void dvmFreeInlineSubsTable()
110{
111    free(gDvm.inlineSubs);
112    gDvm.inlineSubs = NULL;
113}
114
115
116/*
117 * Optimize the specified class.
118 *
119 * If "essentialOnly" is true, we only do essential optimizations.  For
120 * example, accesses to volatile 64-bit fields must be replaced with
121 * "-wide-volatile" instructions or the program could behave incorrectly.
122 * (Skipping non-essential optimizations makes us a little bit faster, and
123 * more importantly avoids dirtying DEX pages.)
124 */
125void dvmOptimizeClass(ClassObject* clazz, bool essentialOnly)
126{
127    int i;
128
129    for (i = 0; i < clazz->directMethodCount; i++) {
130        optimizeMethod(&clazz->directMethods[i], essentialOnly);
131    }
132    for (i = 0; i < clazz->virtualMethodCount; i++) {
133        optimizeMethod(&clazz->virtualMethods[i], essentialOnly);
134    }
135}
136
137/*
138 * Optimize instructions in a method.
139 *
140 * This does a single pass through the code, examining each instruction.
141 *
142 * This is not expected to fail if the class was successfully verified.
143 * The only significant failure modes on unverified code occur when an
144 * "essential" update fails, but we can't generally identify those: if we
145 * can't look up a field, we can't know if the field access was supposed
146 * to be handled as volatile.
147 *
148 * Instead, we give it our best effort, and hope for the best.  For 100%
149 * reliability, only optimize a class after verification succeeds.
150 */
151static void optimizeMethod(Method* method, bool essentialOnly)
152{
153    bool needRetBar, forSmp;
154    u4 insnsSize;
155    u2* insns;
156
157    if (dvmIsNativeMethod(method) || dvmIsAbstractMethod(method))
158        return;
159
160    forSmp = gDvm.dexOptForSmp;
161    needRetBar = needsReturnBarrier(method);
162
163    insns = (u2*) method->insns;
164    assert(insns != NULL);
165    insnsSize = dvmGetMethodInsnsSize(method);
166
167    while (insnsSize > 0) {
168        Opcode opc, quickOpc, volatileOpc;
169        size_t width;
170        bool matched = true;
171
172        opc = dexOpcodeFromCodeUnit(*insns);
173        width = dexGetWidthFromInstruction(insns);
174        volatileOpc = OP_NOP;
175
176        /*
177         * Each instruction may have:
178         * - "volatile" replacement
179         *   - may be essential or essential-on-SMP
180         * - correctness replacement
181         *   - may be essential or essential-on-SMP
182         * - performance replacement
183         *   - always non-essential
184         *
185         * Replacements are considered in the order shown, and the first
186         * match is applied.  For example, iget-wide will convert to
187         * iget-wide-volatile rather than iget-wide-quick if the target
188         * field is volatile.
189         */
190
191        /*
192         * essential substitutions:
193         *  {iget,iput,sget,sput}-wide[/jumbo] --> {op}-wide-volatile
194         *  invoke-direct[/jumbo][/range] --> invoke-object-init/range
195         *
196         * essential-on-SMP substitutions:
197         *  {iget,iput,sget,sput}-*[/jumbo] --> {op}-volatile
198         *  return-void --> return-void-barrier
199         *
200         * non-essential substitutions:
201         *  {iget,iput}-* --> {op}-quick
202         *
203         * TODO: might be time to merge this with the other two switches
204         */
205        switch (opc) {
206        case OP_IGET:
207        case OP_IGET_BOOLEAN:
208        case OP_IGET_BYTE:
209        case OP_IGET_CHAR:
210        case OP_IGET_SHORT:
211            quickOpc = OP_IGET_QUICK;
212            if (forSmp)
213                volatileOpc = OP_IGET_VOLATILE;
214            goto rewrite_inst_field;
215        case OP_IGET_WIDE:
216            quickOpc = OP_IGET_WIDE_QUICK;
217            volatileOpc = OP_IGET_WIDE_VOLATILE;
218            goto rewrite_inst_field;
219        case OP_IGET_OBJECT:
220            quickOpc = OP_IGET_OBJECT_QUICK;
221            if (forSmp)
222                volatileOpc = OP_IGET_OBJECT_VOLATILE;
223            goto rewrite_inst_field;
224        case OP_IPUT:
225        case OP_IPUT_BOOLEAN:
226        case OP_IPUT_BYTE:
227        case OP_IPUT_CHAR:
228        case OP_IPUT_SHORT:
229            quickOpc = OP_IPUT_QUICK;
230            if (forSmp)
231                volatileOpc = OP_IPUT_VOLATILE;
232            goto rewrite_inst_field;
233        case OP_IPUT_WIDE:
234            quickOpc = OP_IPUT_WIDE_QUICK;
235            volatileOpc = OP_IPUT_WIDE_VOLATILE;
236            goto rewrite_inst_field;
237        case OP_IPUT_OBJECT:
238            quickOpc = OP_IPUT_OBJECT_QUICK;
239            if (forSmp)
240                volatileOpc = OP_IPUT_OBJECT_VOLATILE;
241            /* fall through */
242rewrite_inst_field:
243            if (essentialOnly)
244                quickOpc = OP_NOP;      /* if essential-only, no "-quick" sub */
245            if (quickOpc != OP_NOP || volatileOpc != OP_NOP)
246                rewriteInstField(method, insns, quickOpc, volatileOpc);
247            break;
248
249        case OP_IGET_JUMBO:
250        case OP_IGET_BOOLEAN_JUMBO:
251        case OP_IGET_BYTE_JUMBO:
252        case OP_IGET_CHAR_JUMBO:
253        case OP_IGET_SHORT_JUMBO:
254            if (forSmp)
255                volatileOpc = OP_IGET_VOLATILE_JUMBO;
256            goto rewrite_jumbo_inst_field;
257        case OP_IGET_WIDE_JUMBO:
258            volatileOpc = OP_IGET_WIDE_VOLATILE_JUMBO;
259            goto rewrite_jumbo_inst_field;
260        case OP_IGET_OBJECT_JUMBO:
261            if (forSmp)
262                volatileOpc = OP_IGET_OBJECT_VOLATILE_JUMBO;
263            goto rewrite_jumbo_inst_field;
264        case OP_IPUT_JUMBO:
265        case OP_IPUT_BOOLEAN_JUMBO:
266        case OP_IPUT_BYTE_JUMBO:
267        case OP_IPUT_CHAR_JUMBO:
268        case OP_IPUT_SHORT_JUMBO:
269            if (forSmp)
270                volatileOpc = OP_IPUT_VOLATILE_JUMBO;
271            goto rewrite_jumbo_inst_field;
272        case OP_IPUT_WIDE_JUMBO:
273            volatileOpc = OP_IPUT_WIDE_VOLATILE_JUMBO;
274            goto rewrite_jumbo_inst_field;
275        case OP_IPUT_OBJECT_JUMBO:
276            if (forSmp)
277                volatileOpc = OP_IPUT_OBJECT_VOLATILE_JUMBO;
278            /* fall through */
279rewrite_jumbo_inst_field:
280            if (volatileOpc != OP_NOP)
281                rewriteJumboInstField(method, insns, volatileOpc);
282            break;
283
284        case OP_SGET:
285        case OP_SGET_BOOLEAN:
286        case OP_SGET_BYTE:
287        case OP_SGET_CHAR:
288        case OP_SGET_SHORT:
289            if (forSmp)
290                volatileOpc = OP_SGET_VOLATILE;
291            goto rewrite_static_field;
292        case OP_SGET_WIDE:
293            volatileOpc = OP_SGET_WIDE_VOLATILE;
294            goto rewrite_static_field;
295        case OP_SGET_OBJECT:
296            if (forSmp)
297                volatileOpc = OP_SGET_OBJECT_VOLATILE;
298            goto rewrite_static_field;
299        case OP_SPUT:
300        case OP_SPUT_BOOLEAN:
301        case OP_SPUT_BYTE:
302        case OP_SPUT_CHAR:
303        case OP_SPUT_SHORT:
304            if (forSmp)
305                volatileOpc = OP_SPUT_VOLATILE;
306            goto rewrite_static_field;
307        case OP_SPUT_WIDE:
308            volatileOpc = OP_SPUT_WIDE_VOLATILE;
309            goto rewrite_static_field;
310        case OP_SPUT_OBJECT:
311            if (forSmp)
312                volatileOpc = OP_SPUT_OBJECT_VOLATILE;
313            /* fall through */
314rewrite_static_field:
315            if (volatileOpc != OP_NOP)
316                rewriteStaticField(method, insns, volatileOpc);
317            break;
318
319        case OP_SGET_JUMBO:
320        case OP_SGET_BOOLEAN_JUMBO:
321        case OP_SGET_BYTE_JUMBO:
322        case OP_SGET_CHAR_JUMBO:
323        case OP_SGET_SHORT_JUMBO:
324            if (forSmp)
325                volatileOpc = OP_SGET_VOLATILE_JUMBO;
326            goto rewrite_jumbo_static_field;
327        case OP_SGET_WIDE_JUMBO:
328            volatileOpc = OP_SGET_WIDE_VOLATILE_JUMBO;
329            goto rewrite_jumbo_static_field;
330        case OP_SGET_OBJECT_JUMBO:
331            if (forSmp)
332                volatileOpc = OP_SGET_OBJECT_VOLATILE_JUMBO;
333            goto rewrite_jumbo_static_field;
334        case OP_SPUT_JUMBO:
335        case OP_SPUT_BOOLEAN_JUMBO:
336        case OP_SPUT_BYTE_JUMBO:
337        case OP_SPUT_CHAR_JUMBO:
338        case OP_SPUT_SHORT_JUMBO:
339            if (forSmp)
340                volatileOpc = OP_SPUT_VOLATILE_JUMBO;
341            goto rewrite_jumbo_static_field;
342        case OP_SPUT_WIDE_JUMBO:
343            volatileOpc = OP_SPUT_WIDE_VOLATILE_JUMBO;
344            goto rewrite_jumbo_static_field;
345        case OP_SPUT_OBJECT_JUMBO:
346            if (forSmp)
347                volatileOpc = OP_SPUT_OBJECT_VOLATILE_JUMBO;
348            /* fall through */
349rewrite_jumbo_static_field:
350            if (volatileOpc != OP_NOP)
351                rewriteJumboStaticField(method, insns, volatileOpc);
352            break;
353
354        case OP_INVOKE_DIRECT:
355        case OP_INVOKE_DIRECT_RANGE:
356            if (!rewriteInvokeObjectInit(method, insns)) {
357                /* may want to try execute-inline, below */
358                matched = false;
359            }
360            break;
361        case OP_INVOKE_DIRECT_JUMBO:
362            rewriteJumboInvokeObjectInit(method, insns);
363            break;
364        case OP_RETURN_VOID:
365            if (needRetBar)
366                rewriteReturnVoid(method, insns);
367            break;
368        default:
369            matched = false;
370            break;
371        }
372
373
374        /*
375         * non-essential substitutions:
376         *  invoke-{virtual,direct,static}[/range] --> execute-inline
377         *  invoke-{virtual,super}[/range] --> invoke-*-quick
378         */
379        if (!matched && !essentialOnly) {
380            switch (opc) {
381            case OP_INVOKE_VIRTUAL:
382                if (!rewriteExecuteInline(method, insns, METHOD_VIRTUAL)) {
383                    rewriteVirtualInvoke(method, insns,
384                        OP_INVOKE_VIRTUAL_QUICK);
385                }
386                break;
387            case OP_INVOKE_VIRTUAL_RANGE:
388                if (!rewriteExecuteInlineRange(method, insns, METHOD_VIRTUAL)) {
389                    rewriteVirtualInvoke(method, insns,
390                        OP_INVOKE_VIRTUAL_QUICK_RANGE);
391                }
392                break;
393            case OP_INVOKE_SUPER:
394                rewriteVirtualInvoke(method, insns, OP_INVOKE_SUPER_QUICK);
395                break;
396            case OP_INVOKE_SUPER_RANGE:
397                rewriteVirtualInvoke(method, insns, OP_INVOKE_SUPER_QUICK_RANGE);
398                break;
399            case OP_INVOKE_DIRECT:
400                rewriteExecuteInline(method, insns, METHOD_DIRECT);
401                break;
402            case OP_INVOKE_DIRECT_RANGE:
403                rewriteExecuteInlineRange(method, insns, METHOD_DIRECT);
404                break;
405            case OP_INVOKE_STATIC:
406                rewriteExecuteInline(method, insns, METHOD_STATIC);
407                break;
408            case OP_INVOKE_STATIC_RANGE:
409                rewriteExecuteInlineRange(method, insns, METHOD_STATIC);
410                break;
411            default:
412                /* nothing to do for this instruction */
413                ;
414            }
415        }
416
417        assert(width > 0);
418        assert(width <= insnsSize);
419        assert(width == dexGetWidthFromInstruction(insns));
420
421        insns += width;
422        insnsSize -= width;
423    }
424
425    assert(insnsSize == 0);
426}
427
428/*
429 * Update a 16-bit code unit in "meth".  The way in which the DEX data was
430 * loaded determines how we go about the write.
431 *
432 * This will be operating on post-byte-swap DEX data, so values will
433 * be in host order.
434 */
435void dvmUpdateCodeUnit(const Method* meth, u2* ptr, u2 newVal)
436{
437    DvmDex* pDvmDex = meth->clazz->pDvmDex;
438
439    if (!pDvmDex->isMappedReadOnly) {
440        /* in-memory DEX (dexopt or byte[]), alter the output directly */
441        *ptr = newVal;
442    } else {
443        /* memory-mapped file, toggle the page read/write status */
444        dvmDexChangeDex2(pDvmDex, ptr, newVal);
445    }
446}
447
448/*
449 * Update an instruction's opcode.
450 *
451 * If "opcode" is an 8-bit op, we just replace that portion.  If it's a
452 * 16-bit op, we convert the opcode from "packed" form (e.g. 0x0108) to
453 * bytecode form (e.g. 0x08ff).
454 */
455static inline void updateOpcode(const Method* meth, u2* ptr, Opcode opcode)
456{
457    if (opcode >= 256) {
458        /* opcode low byte becomes high byte, low byte becomes 0xff */
459        assert((ptr[0] & 0xff) == 0xff);
460        dvmUpdateCodeUnit(meth, ptr, (u2) (opcode << 8) | 0x00ff);
461    } else {
462        /* 8-bit op, just replace the low byte */
463        assert((ptr[0] & 0xff) != 0xff);
464        dvmUpdateCodeUnit(meth, ptr, (ptr[0] & 0xff00) | (u2) opcode);
465    }
466}
467
468/*
469 * If "referrer" and "resClass" don't come from the same DEX file, and
470 * the DEX we're working on is not destined for the bootstrap class path,
471 * tweak the class loader so package-access checks work correctly.
472 *
473 * Only do this if we're doing pre-verification or optimization.
474 */
475static void tweakLoader(ClassObject* referrer, ClassObject* resClass)
476{
477    if (!gDvm.optimizing)
478        return;
479    assert(referrer->classLoader == NULL);
480    assert(resClass->classLoader == NULL);
481
482    if (!gDvm.optimizingBootstrapClass) {
483        /* class loader for an array class comes from element type */
484        if (dvmIsArrayClass(resClass))
485            resClass = resClass->elementClass;
486        if (referrer->pDvmDex != resClass->pDvmDex)
487            resClass->classLoader = (Object*) 0xdead3333;
488    }
489}
490
491/*
492 * Undo the effects of tweakLoader.
493 */
494static void untweakLoader(ClassObject* referrer, ClassObject* resClass)
495{
496    if (!gDvm.optimizing || gDvm.optimizingBootstrapClass)
497        return;
498
499    if (dvmIsArrayClass(resClass))
500        resClass = resClass->elementClass;
501    resClass->classLoader = NULL;
502}
503
504
505/*
506 * Alternate version of dvmResolveClass for use with verification and
507 * optimization.  Performs access checks on every resolve, and refuses
508 * to acknowledge the existence of classes defined in more than one DEX
509 * file.
510 *
511 * Exceptions caused by failures are cleared before returning.
512 *
513 * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
514 */
515ClassObject* dvmOptResolveClass(ClassObject* referrer, u4 classIdx,
516    VerifyError* pFailure)
517{
518    DvmDex* pDvmDex = referrer->pDvmDex;
519    ClassObject* resClass;
520
521    /*
522     * Check the table first.  If not there, do the lookup by name.
523     */
524    resClass = dvmDexGetResolvedClass(pDvmDex, classIdx);
525    if (resClass == NULL) {
526        const char* className = dexStringByTypeIdx(pDvmDex->pDexFile, classIdx);
527        if (className[0] != '\0' && className[1] == '\0') {
528            /* primitive type */
529            resClass = dvmFindPrimitiveClass(className[0]);
530        } else {
531            resClass = dvmFindClassNoInit(className, referrer->classLoader);
532        }
533        if (resClass == NULL) {
534            /* not found, exception should be raised */
535            LOGV("DexOpt: class %d (%s) not found",
536                classIdx,
537                dexStringByTypeIdx(pDvmDex->pDexFile, classIdx));
538            if (pFailure != NULL) {
539                /* dig through the wrappers to find the original failure */
540                Object* excep = dvmGetException(dvmThreadSelf());
541                while (true) {
542                    Object* cause = dvmGetExceptionCause(excep);
543                    if (cause == NULL)
544                        break;
545                    excep = cause;
546                }
547                if (strcmp(excep->clazz->descriptor,
548                    "Ljava/lang/IncompatibleClassChangeError;") == 0)
549                {
550                    *pFailure = VERIFY_ERROR_CLASS_CHANGE;
551                } else {
552                    *pFailure = VERIFY_ERROR_NO_CLASS;
553                }
554            }
555            dvmClearOptException(dvmThreadSelf());
556            return NULL;
557        }
558
559        /*
560         * Add it to the resolved table so we're faster on the next lookup.
561         */
562        dvmDexSetResolvedClass(pDvmDex, classIdx, resClass);
563    }
564
565    /* multiple definitions? */
566    if (IS_CLASS_FLAG_SET(resClass, CLASS_MULTIPLE_DEFS)) {
567        LOGI("DexOpt: not resolving ambiguous class '%s'",
568            resClass->descriptor);
569        if (pFailure != NULL)
570            *pFailure = VERIFY_ERROR_NO_CLASS;
571        return NULL;
572    }
573
574    /* access allowed? */
575    tweakLoader(referrer, resClass);
576    bool allowed = dvmCheckClassAccess(referrer, resClass);
577    untweakLoader(referrer, resClass);
578    if (!allowed) {
579        LOGW("DexOpt: resolve class illegal access: %s -> %s",
580            referrer->descriptor, resClass->descriptor);
581        if (pFailure != NULL)
582            *pFailure = VERIFY_ERROR_ACCESS_CLASS;
583        return NULL;
584    }
585
586    return resClass;
587}
588
589/*
590 * Alternate version of dvmResolveInstField().
591 *
592 * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
593 */
594InstField* dvmOptResolveInstField(ClassObject* referrer, u4 ifieldIdx,
595    VerifyError* pFailure)
596{
597    DvmDex* pDvmDex = referrer->pDvmDex;
598    InstField* resField;
599
600    resField = (InstField*) dvmDexGetResolvedField(pDvmDex, ifieldIdx);
601    if (resField == NULL) {
602        const DexFieldId* pFieldId;
603        ClassObject* resClass;
604
605        pFieldId = dexGetFieldId(pDvmDex->pDexFile, ifieldIdx);
606
607        /*
608         * Find the field's class.
609         */
610        resClass = dvmOptResolveClass(referrer, pFieldId->classIdx, pFailure);
611        if (resClass == NULL) {
612            //dvmClearOptException(dvmThreadSelf());
613            assert(!dvmCheckException(dvmThreadSelf()));
614            if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); }
615            return NULL;
616        }
617
618        resField = (InstField*)dvmFindFieldHier(resClass,
619            dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx),
620            dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx));
621        if (resField == NULL) {
622            LOGD("DexOpt: couldn't find field %s.%s",
623                resClass->descriptor,
624                dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx));
625            if (pFailure != NULL)
626                *pFailure = VERIFY_ERROR_NO_FIELD;
627            return NULL;
628        }
629        if (dvmIsStaticField(resField)) {
630            LOGD("DexOpt: wanted instance, got static for field %s.%s",
631                resClass->descriptor,
632                dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx));
633            if (pFailure != NULL)
634                *pFailure = VERIFY_ERROR_CLASS_CHANGE;
635            return NULL;
636        }
637
638        /*
639         * Add it to the resolved table so we're faster on the next lookup.
640         */
641        dvmDexSetResolvedField(pDvmDex, ifieldIdx, (Field*) resField);
642    }
643
644    /* access allowed? */
645    tweakLoader(referrer, resField->clazz);
646    bool allowed = dvmCheckFieldAccess(referrer, (Field*)resField);
647    untweakLoader(referrer, resField->clazz);
648    if (!allowed) {
649        LOGI("DexOpt: access denied from %s to field %s.%s",
650            referrer->descriptor, resField->clazz->descriptor,
651            resField->name);
652        if (pFailure != NULL)
653            *pFailure = VERIFY_ERROR_ACCESS_FIELD;
654        return NULL;
655    }
656
657    return resField;
658}
659
660/*
661 * Alternate version of dvmResolveStaticField().
662 *
663 * Does not force initialization of the resolved field's class.
664 *
665 * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
666 */
667StaticField* dvmOptResolveStaticField(ClassObject* referrer, u4 sfieldIdx,
668    VerifyError* pFailure)
669{
670    DvmDex* pDvmDex = referrer->pDvmDex;
671    StaticField* resField;
672
673    resField = (StaticField*)dvmDexGetResolvedField(pDvmDex, sfieldIdx);
674    if (resField == NULL) {
675        const DexFieldId* pFieldId;
676        ClassObject* resClass;
677
678        pFieldId = dexGetFieldId(pDvmDex->pDexFile, sfieldIdx);
679
680        /*
681         * Find the field's class.
682         */
683        resClass = dvmOptResolveClass(referrer, pFieldId->classIdx, pFailure);
684        if (resClass == NULL) {
685            //dvmClearOptException(dvmThreadSelf());
686            assert(!dvmCheckException(dvmThreadSelf()));
687            if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); }
688            return NULL;
689        }
690
691        const char* fieldName =
692            dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx);
693
694        resField = (StaticField*)dvmFindFieldHier(resClass, fieldName,
695                    dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx));
696        if (resField == NULL) {
697            LOGD("DexOpt: couldn't find static field %s.%s",
698                resClass->descriptor, fieldName);
699            if (pFailure != NULL)
700                *pFailure = VERIFY_ERROR_NO_FIELD;
701            return NULL;
702        }
703        if (!dvmIsStaticField(resField)) {
704            LOGD("DexOpt: wanted static, got instance for field %s.%s",
705                resClass->descriptor, fieldName);
706            if (pFailure != NULL)
707                *pFailure = VERIFY_ERROR_CLASS_CHANGE;
708            return NULL;
709        }
710
711        /*
712         * Add it to the resolved table so we're faster on the next lookup.
713         *
714         * We can only do this if we're in "dexopt", because the presence
715         * of a valid value in the resolution table implies that the class
716         * containing the static field has been initialized.
717         */
718        if (gDvm.optimizing)
719            dvmDexSetResolvedField(pDvmDex, sfieldIdx, (Field*) resField);
720    }
721
722    /* access allowed? */
723    tweakLoader(referrer, resField->clazz);
724    bool allowed = dvmCheckFieldAccess(referrer, (Field*)resField);
725    untweakLoader(referrer, resField->clazz);
726    if (!allowed) {
727        LOGI("DexOpt: access denied from %s to field %s.%s",
728            referrer->descriptor, resField->clazz->descriptor,
729            resField->name);
730        if (pFailure != NULL)
731            *pFailure = VERIFY_ERROR_ACCESS_FIELD;
732        return NULL;
733    }
734
735    return resField;
736}
737
738
739/*
740 * Rewrite an iget/iput instruction if appropriate.  These all have the form:
741 *   op vA, vB, field@CCCC
742 *
743 * Where vA holds the value, vB holds the object reference, and CCCC is
744 * the field reference constant pool offset.  For a non-volatile field,
745 * we want to replace the opcode with "quickOpc" and replace CCCC with
746 * the byte offset from the start of the object.  For a volatile field,
747 * we just want to replace the opcode with "volatileOpc".
748 *
749 * If "volatileOpc" is OP_NOP we don't check to see if it's a volatile
750 * field.  If "quickOpc" is OP_NOP, and this is a non-volatile field,
751 * we don't do anything.
752 *
753 * "method" is the referring method.
754 */
755static void rewriteInstField(Method* method, u2* insns, Opcode quickOpc,
756    Opcode volatileOpc)
757{
758    ClassObject* clazz = method->clazz;
759    u2 fieldIdx = insns[1];
760    InstField* instField;
761
762    instField = dvmOptResolveInstField(clazz, fieldIdx, NULL);
763    if (instField == NULL) {
764        LOGI("DexOpt: unable to optimize instance field ref "
765             "0x%04x at 0x%02x in %s.%s\n",
766            fieldIdx, (int) (insns - method->insns), clazz->descriptor,
767            method->name);
768        return;
769    }
770
771    if (volatileOpc != OP_NOP && dvmIsVolatileField(instField)) {
772        updateOpcode(method, insns, volatileOpc);
773        LOGV("DexOpt: rewrote ifield access %s.%s --> volatile",
774            instField->clazz->descriptor, instField->name);
775    } else if (quickOpc != OP_NOP && instField->byteOffset < 65536) {
776        updateOpcode(method, insns, quickOpc);
777        dvmUpdateCodeUnit(method, insns+1, (u2) instField->byteOffset);
778        LOGV("DexOpt: rewrote ifield access %s.%s --> %d",
779            instField->clazz->descriptor, instField->name,
780            instField->byteOffset);
781    } else {
782        LOGV("DexOpt: no rewrite of ifield access %s.%s",
783            instField->clazz->descriptor, instField->name);
784    }
785
786    return;
787}
788
789/*
790 * Rewrite a jumbo instance field access instruction if appropriate.  If
791 * the target field is volatile, we replace the opcode with "volatileOpc".
792 *
793 * "method" is the referring method.
794 */
795static void rewriteJumboInstField(Method* method, u2* insns, Opcode volatileOpc)
796{
797    ClassObject* clazz = method->clazz;
798    u4 fieldIdx = insns[1] | (u4) insns[2] << 16;
799    InstField* instField;
800
801    assert(volatileOpc != OP_NOP);
802
803    instField = dvmOptResolveInstField(clazz, fieldIdx, NULL);
804    if (instField == NULL) {
805        LOGI("DexOpt: unable to optimize instance field ref "
806             "0x%04x at 0x%02x in %s.%s\n",
807            fieldIdx, (int) (insns - method->insns), clazz->descriptor,
808            method->name);
809        return;
810    }
811
812    if (dvmIsVolatileField(instField)) {
813        updateOpcode(method, insns, volatileOpc);
814        LOGV("DexOpt: rewrote jumbo ifield access %s.%s --> volatile",
815            instField->clazz->descriptor, instField->name);
816    } else {
817        LOGV("DexOpt: no rewrite of jumbo ifield access %s.%s",
818            instField->clazz->descriptor, instField->name);
819    }
820}
821
822/*
823 * Rewrite a static [jumbo] field access instruction if appropriate.  If
824 * the target field is volatile, we replace the opcode with "volatileOpc".
825 *
826 * "method" is the referring method.
827 */
828static void rewriteStaticField0(Method* method, u2* insns, Opcode volatileOpc,
829    u4 fieldIdx)
830{
831    ClassObject* clazz = method->clazz;
832    StaticField* staticField;
833
834    assert(volatileOpc != OP_NOP);
835
836    staticField = dvmOptResolveStaticField(clazz, fieldIdx, NULL);
837    if (staticField == NULL) {
838        LOGI("DexOpt: unable to optimize static field ref "
839             "0x%04x at 0x%02x in %s.%s\n",
840            fieldIdx, (int) (insns - method->insns), clazz->descriptor,
841            method->name);
842        return;
843    }
844
845    if (dvmIsVolatileField(staticField)) {
846        updateOpcode(method, insns, volatileOpc);
847        LOGV("DexOpt: rewrote sfield access %s.%s --> volatile",
848            staticField->clazz->descriptor, staticField->name);
849    }
850}
851
852static void rewriteStaticField(Method* method, u2* insns, Opcode volatileOpc)
853{
854    u2 fieldIdx = insns[1];
855    rewriteStaticField0(method, insns, volatileOpc, fieldIdx);
856}
857static void rewriteJumboStaticField(Method* method, u2* insns,
858    Opcode volatileOpc)
859{
860    u4 fieldIdx = insns[1] | (u4) insns[2] << 16;
861    rewriteStaticField0(method, insns, volatileOpc, fieldIdx);
862}
863
864
865/*
866 * Alternate version of dvmResolveMethod().
867 *
868 * Doesn't throw exceptions, and checks access on every lookup.
869 *
870 * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
871 */
872Method* dvmOptResolveMethod(ClassObject* referrer, u4 methodIdx,
873    MethodType methodType, VerifyError* pFailure)
874{
875    DvmDex* pDvmDex = referrer->pDvmDex;
876    Method* resMethod;
877
878    assert(methodType == METHOD_DIRECT ||
879           methodType == METHOD_VIRTUAL ||
880           methodType == METHOD_STATIC);
881
882    LOGVV("--- resolving method %u (referrer=%s)", methodIdx,
883        referrer->descriptor);
884
885    resMethod = dvmDexGetResolvedMethod(pDvmDex, methodIdx);
886    if (resMethod == NULL) {
887        const DexMethodId* pMethodId;
888        ClassObject* resClass;
889
890        pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx);
891
892        resClass = dvmOptResolveClass(referrer, pMethodId->classIdx, pFailure);
893        if (resClass == NULL) {
894            /*
895             * Can't find the class that the method is a part of, or don't
896             * have permission to access the class.
897             */
898            LOGV("DexOpt: can't find called method's class (?.%s)",
899                dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx));
900            if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); }
901            return NULL;
902        }
903        if (dvmIsInterfaceClass(resClass)) {
904            /* method is part of an interface; this is wrong method for that */
905            LOGW("DexOpt: method is in an interface");
906            if (pFailure != NULL)
907                *pFailure = VERIFY_ERROR_GENERIC;
908            return NULL;
909        }
910
911        /*
912         * We need to chase up the class hierarchy to find methods defined
913         * in super-classes.  (We only want to check the current class
914         * if we're looking for a constructor.)
915         */
916        DexProto proto;
917        dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId);
918
919        if (methodType == METHOD_DIRECT) {
920            resMethod = dvmFindDirectMethod(resClass,
921                dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx), &proto);
922        } else {
923            /* METHOD_STATIC or METHOD_VIRTUAL */
924            resMethod = dvmFindMethodHier(resClass,
925                dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx), &proto);
926        }
927
928        if (resMethod == NULL) {
929            LOGV("DexOpt: couldn't find method '%s'",
930                dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx));
931            if (pFailure != NULL)
932                *pFailure = VERIFY_ERROR_NO_METHOD;
933            return NULL;
934        }
935        if (methodType == METHOD_STATIC) {
936            if (!dvmIsStaticMethod(resMethod)) {
937                LOGD("DexOpt: wanted static, got instance for method %s.%s",
938                    resClass->descriptor, resMethod->name);
939                if (pFailure != NULL)
940                    *pFailure = VERIFY_ERROR_CLASS_CHANGE;
941                return NULL;
942            }
943        } else if (methodType == METHOD_VIRTUAL) {
944            if (dvmIsStaticMethod(resMethod)) {
945                LOGD("DexOpt: wanted instance, got static for method %s.%s",
946                    resClass->descriptor, resMethod->name);
947                if (pFailure != NULL)
948                    *pFailure = VERIFY_ERROR_CLASS_CHANGE;
949                return NULL;
950            }
951        }
952
953        /* see if this is a pure-abstract method */
954        if (dvmIsAbstractMethod(resMethod) && !dvmIsAbstractClass(resClass)) {
955            LOGW("DexOpt: pure-abstract method '%s' in %s",
956                dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx),
957                resClass->descriptor);
958            if (pFailure != NULL)
959                *pFailure = VERIFY_ERROR_GENERIC;
960            return NULL;
961        }
962
963        /*
964         * Add it to the resolved table so we're faster on the next lookup.
965         *
966         * We can only do this for static methods if we're not in "dexopt",
967         * because the presence of a valid value in the resolution table
968         * implies that the class containing the static field has been
969         * initialized.
970         */
971        if (methodType != METHOD_STATIC || gDvm.optimizing)
972            dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod);
973    }
974
975    LOGVV("--- found method %d (%s.%s)",
976        methodIdx, resMethod->clazz->descriptor, resMethod->name);
977
978    /* access allowed? */
979    tweakLoader(referrer, resMethod->clazz);
980    bool allowed = dvmCheckMethodAccess(referrer, resMethod);
981    untweakLoader(referrer, resMethod->clazz);
982    if (!allowed) {
983        IF_LOGI() {
984            char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
985            LOGI("DexOpt: illegal method access (call %s.%s %s from %s)",
986                resMethod->clazz->descriptor, resMethod->name, desc,
987                referrer->descriptor);
988            free(desc);
989        }
990        if (pFailure != NULL)
991            *pFailure = VERIFY_ERROR_ACCESS_METHOD;
992        return NULL;
993    }
994
995    return resMethod;
996}
997
998/*
999 * Rewrite invoke-virtual, invoke-virtual/range, invoke-super, and
1000 * invoke-super/range if appropriate.  These all have the form:
1001 *   op vAA, meth@BBBB, reg stuff @CCCC
1002 *
1003 * We want to replace the method constant pool index BBBB with the
1004 * vtable index.
1005 */
1006static void rewriteVirtualInvoke(Method* method, u2* insns, Opcode newOpc)
1007{
1008    ClassObject* clazz = method->clazz;
1009    Method* baseMethod;
1010    u2 methodIdx = insns[1];
1011
1012    baseMethod = dvmOptResolveMethod(clazz, methodIdx, METHOD_VIRTUAL, NULL);
1013    if (baseMethod == NULL) {
1014        LOGD("DexOpt: unable to optimize virt call 0x%04x at 0x%02x in %s.%s",
1015            methodIdx,
1016            (int) (insns - method->insns), clazz->descriptor,
1017            method->name);
1018        return;
1019    }
1020
1021    assert((insns[0] & 0xff) == OP_INVOKE_VIRTUAL ||
1022           (insns[0] & 0xff) == OP_INVOKE_VIRTUAL_RANGE ||
1023           (insns[0] & 0xff) == OP_INVOKE_SUPER ||
1024           (insns[0] & 0xff) == OP_INVOKE_SUPER_RANGE);
1025
1026    /*
1027     * Note: Method->methodIndex is a u2 and is range checked during the
1028     * initial load.
1029     */
1030    updateOpcode(method, insns, newOpc);
1031    dvmUpdateCodeUnit(method, insns+1, baseMethod->methodIndex);
1032
1033    //LOGI("DexOpt: rewrote call to %s.%s --> %s.%s",
1034    //    method->clazz->descriptor, method->name,
1035    //    baseMethod->clazz->descriptor, baseMethod->name);
1036
1037    return;
1038}
1039
1040/*
1041 * Rewrite invoke-direct[/range] if the target is Object.<init>.
1042 *
1043 * This is useful as an optimization, because otherwise every object
1044 * instantiation will cause us to call a method that does nothing.
1045 * It also allows us to inexpensively mark objects as finalizable at the
1046 * correct time.
1047 *
1048 * TODO: verifier should ensure Object.<init> contains only return-void,
1049 * and issue a warning if not.
1050 */
1051static bool rewriteInvokeObjectInit(Method* method, u2* insns)
1052{
1053    ClassObject* clazz = method->clazz;
1054    Method* calledMethod;
1055    u2 methodIdx = insns[1];
1056
1057    calledMethod = dvmOptResolveMethod(clazz, methodIdx, METHOD_DIRECT, NULL);
1058    if (calledMethod == NULL) {
1059        LOGD("DexOpt: unable to opt direct call 0x%04x at 0x%02x in %s.%s",
1060            methodIdx, (int) (insns - method->insns),
1061            clazz->descriptor, method->name);
1062        return false;
1063    }
1064
1065    if (calledMethod->clazz == gDvm.classJavaLangObject &&
1066        dvmCompareNameDescriptorAndMethod("<init>", "()V", calledMethod) == 0)
1067    {
1068        /*
1069         * Replace the instruction.  If the debugger is attached, the
1070         * interpreter will forward execution to the invoke-direct/range
1071         * handler.  If this was an invoke-direct/range instruction we can
1072         * just replace the opcode, but if it was an invoke-direct we
1073         * have to set the argument count (high 8 bits of first code unit)
1074         * to 1.
1075         */
1076        u1 origOp = insns[0] & 0xff;
1077        if (origOp == OP_INVOKE_DIRECT) {
1078            dvmUpdateCodeUnit(method, insns,
1079                OP_INVOKE_OBJECT_INIT_RANGE | 0x100);
1080        } else {
1081            assert(origOp == OP_INVOKE_DIRECT_RANGE);
1082            assert((insns[0] >> 8) == 1);
1083            updateOpcode(method, insns, OP_INVOKE_OBJECT_INIT_RANGE);
1084        }
1085
1086        LOGVV("DexOpt: replaced Object.<init> in %s.%s",
1087            method->clazz->descriptor, method->name);
1088    }
1089
1090    return true;
1091}
1092
1093/*
1094 * Rewrite invoke-direct/jumbo if the target is Object.<init>.
1095 */
1096static bool rewriteJumboInvokeObjectInit(Method* method, u2* insns)
1097{
1098    ClassObject* clazz = method->clazz;
1099    Method* calledMethod;
1100    u4 methodIdx = insns[1] | (u4) insns[2] << 16;
1101
1102    calledMethod = dvmOptResolveMethod(clazz, methodIdx, METHOD_DIRECT, NULL);
1103    if (calledMethod == NULL) {
1104        LOGD("DexOpt: unable to opt direct call 0x%04x at 0x%02x in %s.%s",
1105            methodIdx, (int) (insns - method->insns),
1106            clazz->descriptor, method->name);
1107        return false;
1108    }
1109
1110    if (calledMethod->clazz == gDvm.classJavaLangObject &&
1111        dvmCompareNameDescriptorAndMethod("<init>", "()V", calledMethod) == 0)
1112    {
1113        assert(insns[0] == ((u2) (OP_INVOKE_DIRECT_JUMBO << 8) | 0xff));
1114        updateOpcode(method, insns, OP_INVOKE_OBJECT_INIT_JUMBO);
1115
1116        LOGVV("DexOpt: replaced jumbo Object.<init> in %s.%s",
1117            method->clazz->descriptor, method->name);
1118    }
1119
1120    return true;
1121}
1122
1123/*
1124 * Resolve an interface method reference.
1125 *
1126 * No method access check here -- interface methods are always public.
1127 *
1128 * Returns NULL if the method was not found.  Does not throw an exception.
1129 */
1130Method* dvmOptResolveInterfaceMethod(ClassObject* referrer, u4 methodIdx)
1131{
1132    DvmDex* pDvmDex = referrer->pDvmDex;
1133    Method* resMethod;
1134
1135    LOGVV("--- resolving interface method %d (referrer=%s)",
1136        methodIdx, referrer->descriptor);
1137
1138    resMethod = dvmDexGetResolvedMethod(pDvmDex, methodIdx);
1139    if (resMethod == NULL) {
1140        const DexMethodId* pMethodId;
1141        ClassObject* resClass;
1142
1143        pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx);
1144
1145        resClass = dvmOptResolveClass(referrer, pMethodId->classIdx, NULL);
1146        if (resClass == NULL) {
1147            /* can't find the class that the method is a part of */
1148            dvmClearOptException(dvmThreadSelf());
1149            return NULL;
1150        }
1151        if (!dvmIsInterfaceClass(resClass)) {
1152            /* whoops */
1153            LOGI("Interface method not part of interface class");
1154            return NULL;
1155        }
1156
1157        const char* methodName =
1158            dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx);
1159        DexProto proto;
1160        dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId);
1161
1162        LOGVV("+++ looking for '%s' '%s' in resClass='%s'",
1163            methodName, methodSig, resClass->descriptor);
1164        resMethod = dvmFindInterfaceMethodHier(resClass, methodName, &proto);
1165        if (resMethod == NULL) {
1166            return NULL;
1167        }
1168
1169        /* we're expecting this to be abstract */
1170        if (!dvmIsAbstractMethod(resMethod)) {
1171            char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
1172            LOGW("Found non-abstract interface method %s.%s %s",
1173                resMethod->clazz->descriptor, resMethod->name, desc);
1174            free(desc);
1175            return NULL;
1176        }
1177
1178        /*
1179         * Add it to the resolved table so we're faster on the next lookup.
1180         */
1181        dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod);
1182    }
1183
1184    LOGVV("--- found interface method %d (%s.%s)",
1185        methodIdx, resMethod->clazz->descriptor, resMethod->name);
1186
1187    /* interface methods are always public; no need to check access */
1188
1189    return resMethod;
1190}
1191
1192/*
1193 * Replace invoke-virtual, invoke-direct, or invoke-static with an
1194 * execute-inline operation if appropriate.
1195 *
1196 * Returns "true" if we replace it.
1197 */
1198static bool rewriteExecuteInline(Method* method, u2* insns,
1199    MethodType methodType)
1200{
1201    const InlineSub* inlineSubs = gDvm.inlineSubs;
1202    ClassObject* clazz = method->clazz;
1203    Method* calledMethod;
1204    u2 methodIdx = insns[1];
1205
1206    //return false;
1207
1208    calledMethod = dvmOptResolveMethod(clazz, methodIdx, methodType, NULL);
1209    if (calledMethod == NULL) {
1210        LOGV("+++ DexOpt inline: can't find %d", methodIdx);
1211        return false;
1212    }
1213
1214    while (inlineSubs->method != NULL) {
1215        /*
1216        if (extra) {
1217            LOGI("comparing %p vs %p %s.%s %s",
1218                inlineSubs->method, calledMethod,
1219                inlineSubs->method->clazz->descriptor,
1220                inlineSubs->method->name,
1221                inlineSubs->method->signature);
1222        }
1223        */
1224        if (inlineSubs->method == calledMethod) {
1225            assert((insns[0] & 0xff) == OP_INVOKE_DIRECT ||
1226                   (insns[0] & 0xff) == OP_INVOKE_STATIC ||
1227                   (insns[0] & 0xff) == OP_INVOKE_VIRTUAL);
1228            updateOpcode(method, insns, OP_EXECUTE_INLINE);
1229            dvmUpdateCodeUnit(method, insns+1, (u2) inlineSubs->inlineIdx);
1230
1231            //LOGI("DexOpt: execute-inline %s.%s --> %s.%s",
1232            //    method->clazz->descriptor, method->name,
1233            //    calledMethod->clazz->descriptor, calledMethod->name);
1234            return true;
1235        }
1236
1237        inlineSubs++;
1238    }
1239
1240    return false;
1241}
1242
1243/*
1244 * Replace invoke-virtual/range, invoke-direct/range, or invoke-static/range
1245 * with an execute-inline operation if appropriate.
1246 *
1247 * Returns "true" if we replace it.
1248 */
1249static bool rewriteExecuteInlineRange(Method* method, u2* insns,
1250    MethodType methodType)
1251{
1252    const InlineSub* inlineSubs = gDvm.inlineSubs;
1253    ClassObject* clazz = method->clazz;
1254    Method* calledMethod;
1255    u2 methodIdx = insns[1];
1256
1257    calledMethod = dvmOptResolveMethod(clazz, methodIdx, methodType, NULL);
1258    if (calledMethod == NULL) {
1259        LOGV("+++ DexOpt inline/range: can't find %d", methodIdx);
1260        return false;
1261    }
1262
1263    while (inlineSubs->method != NULL) {
1264        if (inlineSubs->method == calledMethod) {
1265            assert((insns[0] & 0xff) == OP_INVOKE_DIRECT_RANGE ||
1266                   (insns[0] & 0xff) == OP_INVOKE_STATIC_RANGE ||
1267                   (insns[0] & 0xff) == OP_INVOKE_VIRTUAL_RANGE);
1268            updateOpcode(method, insns, OP_EXECUTE_INLINE_RANGE);
1269            dvmUpdateCodeUnit(method, insns+1, (u2) inlineSubs->inlineIdx);
1270
1271            //LOGI("DexOpt: execute-inline/range %s.%s --> %s.%s",
1272            //    method->clazz->descriptor, method->name,
1273            //    calledMethod->clazz->descriptor, calledMethod->name);
1274            return true;
1275        }
1276
1277        inlineSubs++;
1278    }
1279
1280    return false;
1281}
1282
1283/*
1284 * Returns "true" if the return-void instructions in this method should
1285 * be converted to return-void-barrier.
1286 *
1287 * This is needed to satisfy a Java Memory Model requirement regarding
1288 * the construction of objects with final fields.  (This does not apply
1289 * to <clinit> or static fields, since appropriate barriers are guaranteed
1290 * by the class initialization process.)
1291 */
1292static bool needsReturnBarrier(Method* method)
1293{
1294    if (!gDvm.dexOptForSmp)
1295        return false;
1296    if (strcmp(method->name, "<init>") != 0)
1297        return false;
1298
1299    /*
1300     * Check to see if the class is finalizable.  The loader sets a flag
1301     * if the class or one of its superclasses overrides finalize().
1302     */
1303    const ClassObject* clazz = method->clazz;
1304    if (IS_CLASS_FLAG_SET(clazz, CLASS_ISFINALIZABLE))
1305        return true;
1306
1307    /*
1308     * Check to see if the class has any final fields.  If not, we don't
1309     * need to generate a barrier instruction.
1310     *
1311     * In theory, we only need to do this if the method actually modifies
1312     * a final field.  In practice, non-constructor methods are allowed
1313     * to modify final fields, and there are 3rd-party tools that rely on
1314     * this behavior.  (The compiler does not allow it, but the VM does.)
1315     *
1316     * If we alter the verifier to restrict final-field updates to
1317     * constructors, we can tighten this up as well.
1318     */
1319    int idx = clazz->ifieldCount;
1320    while (--idx >= 0) {
1321        if (dvmIsFinalField(&clazz->ifields[idx]))
1322            return true;
1323    }
1324
1325    return false;
1326}
1327
1328/*
1329 * Convert a return-void to a return-void-barrier.
1330 */
1331static void rewriteReturnVoid(Method* method, u2* insns)
1332{
1333    assert((insns[0] & 0xff) == OP_RETURN_VOID);
1334    updateOpcode(method, insns, OP_RETURN_VOID_BARRIER);
1335}
1336