InlineTransformation.cpp revision 5d5b94c8d14b166af580d5dd5906db4f9527d6ca
17a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng/*
27a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng * Copyright (C) 2010 The Android Open Source Project
37a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng *
47a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng * Licensed under the Apache License, Version 2.0 (the "License");
57a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng * you may not use this file except in compliance with the License.
67a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng * You may obtain a copy of the License at
77a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng *
87a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng *      http://www.apache.org/licenses/LICENSE-2.0
97a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng *
107a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng * Unless required by applicable law or agreed to in writing, software
117a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng * distributed under the License is distributed on an "AS IS" BASIS,
127a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng * See the License for the specific language governing permissions and
147a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng * limitations under the License.
157a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng */
167a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
177a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng#include "Dalvik.h"
187a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng#include "Dataflow.h"
19df4daaf8f41e3dcaa8221f54273338160dd43138Dan Bornstein#include "libdex/DexOpcodes.h"
207a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
217a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng/* Convert the reg id from the callee to the original id passed by the caller */
227a2697d327936e20ef5484f7819e2e4bf91c891fBen Chengstatic inline u4 convertRegId(const DecodedInstruction *invoke,
237a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng                              const Method *calleeMethod,
247a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng                              int calleeRegId, bool isRange)
257a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng{
267a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    /* The order in the original arg passing list */
277a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    int rank = calleeRegId -
287a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng               (calleeMethod->registersSize - calleeMethod->insSize);
297a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    assert(rank >= 0);
307a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    if (!isRange) {
317a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng        return invoke->arg[rank];
327a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    } else {
337a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng        return invoke->vC + rank;
347a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    }
357a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng}
367a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
37cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Chengstatic bool inlineGetter(CompilationUnit *cUnit,
387a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng                         const Method *calleeMethod,
397a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng                         MIR *invokeMIR,
407a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng                         BasicBlock *invokeBB,
417a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng                         bool isPredicted,
427a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng                         bool isRange)
437a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng{
447a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    BasicBlock *moveResultBB = invokeBB->fallThrough;
457a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    MIR *moveResultMIR = moveResultBB->firstMIRInsn;
46fc75f3ed87b55d625b6054e18645da5cbdba31c6Carl Shapiro    MIR *newGetterMIR = (MIR *)dvmCompilerNew(sizeof(MIR), true);
477a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    DecodedInstruction getterInsn;
487a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
49543223954993a19fa96670692bc7aa55d851966bDan Bornstein    dexDecodeInstruction(calleeMethod->insns, &getterInsn);
507a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
517a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    if (!dvmCompilerCanIncludeThisInstruction(calleeMethod, &getterInsn))
52cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng        return false;
537a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
547a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    /*
557a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng     * Some getters (especially invoked through interface) are not followed
567a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng     * by a move result.
577a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng     */
587a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    if ((moveResultMIR == NULL) ||
599a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornstein        (moveResultMIR->dalvikInsn.opcode != OP_MOVE_RESULT &&
609a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornstein         moveResultMIR->dalvikInsn.opcode != OP_MOVE_RESULT_OBJECT &&
619a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornstein         moveResultMIR->dalvikInsn.opcode != OP_MOVE_RESULT_WIDE)) {
62cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng        return false;
637a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    }
647a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
659a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornstein    int dfFlags = dvmCompilerDataFlowAttributes[getterInsn.opcode];
667a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
677a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    /* Expecting vA to be the destination register */
6852d4cd28a5d6d946934704e11e1d41450c10aa05Ben Cheng    if (dfFlags & (DF_UA | DF_UA_WIDE)) {
699a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornstein        LOGE("opcode %d has DF_UA set (not expected)", getterInsn.opcode);
707a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng        dvmAbort();
717a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    }
727a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
737a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    if (dfFlags & DF_UB) {
747a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng        getterInsn.vB = convertRegId(&invokeMIR->dalvikInsn, calleeMethod,
757a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng                                     getterInsn.vB, isRange);
767a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    }
777a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
787a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    if (dfFlags & DF_UC) {
797a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng        getterInsn.vC = convertRegId(&invokeMIR->dalvikInsn, calleeMethod,
807a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng                                     getterInsn.vC, isRange);
817a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    }
827a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
837a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    getterInsn.vA = moveResultMIR->dalvikInsn.vA;
847a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
857a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    /* Now setup the Dalvik instruction with converted src/dst registers */
867a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    newGetterMIR->dalvikInsn = getterInsn;
877a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
88e485276c6ba778cafa373b3b5c867f84e91b0bfdDan Bornstein    newGetterMIR->width = dexGetWidthFromOpcode(getterInsn.opcode);
897a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
907a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    newGetterMIR->OptimizationFlags |= MIR_CALLEE;
917a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
927a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    /*
937a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng     * If the getter instruction is about to raise any exception, punt to the
947a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng     * interpreter and re-execute the invoke.
957a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng     */
967a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    newGetterMIR->offset = invokeMIR->offset;
977a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
987a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    newGetterMIR->meta.calleeMethod = calleeMethod;
997a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
1007a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    dvmCompilerInsertMIRAfter(invokeBB, invokeMIR, newGetterMIR);
1017a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
1027a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    if (isPredicted) {
103fc75f3ed87b55d625b6054e18645da5cbdba31c6Carl Shapiro        MIR *invokeMIRSlow = (MIR *)dvmCompilerNew(sizeof(MIR), true);
1047a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng        *invokeMIRSlow = *invokeMIR;
1055d5b94c8d14b166af580d5dd5906db4f9527d6caCarl Shapiro        invokeMIR->dalvikInsn.opcode = (Opcode)kMirOpCheckInlinePrediction;
1067a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
1077a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng        /* Use vC to denote the first argument (ie this) */
1087a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng        if (!isRange) {
1097a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng            invokeMIR->dalvikInsn.vC = invokeMIRSlow->dalvikInsn.arg[0];
1107a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng        }
1117a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
1127a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng        moveResultMIR->OptimizationFlags |= MIR_INLINED_PRED;
1137a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
1147a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng        dvmCompilerInsertMIRAfter(invokeBB, newGetterMIR, invokeMIRSlow);
1157a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng        invokeMIRSlow->OptimizationFlags |= MIR_INLINED_PRED;
1167a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng#if defined(WITH_JIT_TUNING)
1177a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng        gDvmJit.invokePolyGetterInlined++;
1187a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng#endif
1197a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    } else {
1207a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng        invokeMIR->OptimizationFlags |= MIR_INLINED;
1217a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng        moveResultMIR->OptimizationFlags |= MIR_INLINED;
1227a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng#if defined(WITH_JIT_TUNING)
1237a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng        gDvmJit.invokeMonoGetterInlined++;
1247a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng#endif
1257a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    }
1267a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
127cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng    return true;
1287a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng}
1297a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
130cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Chengstatic bool inlineSetter(CompilationUnit *cUnit,
1317a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng                         const Method *calleeMethod,
1327a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng                         MIR *invokeMIR,
1337a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng                         BasicBlock *invokeBB,
1347a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng                         bool isPredicted,
1357a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng                         bool isRange)
1367a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng{
137fc75f3ed87b55d625b6054e18645da5cbdba31c6Carl Shapiro    MIR *newSetterMIR = (MIR *)dvmCompilerNew(sizeof(MIR), true);
1387a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    DecodedInstruction setterInsn;
1397a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
140543223954993a19fa96670692bc7aa55d851966bDan Bornstein    dexDecodeInstruction(calleeMethod->insns, &setterInsn);
1417a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
1427a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    if (!dvmCompilerCanIncludeThisInstruction(calleeMethod, &setterInsn))
143cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng        return false;
1447a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
1459a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornstein    int dfFlags = dvmCompilerDataFlowAttributes[setterInsn.opcode];
1467a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
14752d4cd28a5d6d946934704e11e1d41450c10aa05Ben Cheng    if (dfFlags & (DF_UA | DF_UA_WIDE)) {
1487a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng        setterInsn.vA = convertRegId(&invokeMIR->dalvikInsn, calleeMethod,
1497a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng                                     setterInsn.vA, isRange);
1507a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
1517a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    }
1527a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
1537a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    if (dfFlags & DF_UB) {
1547a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng        setterInsn.vB = convertRegId(&invokeMIR->dalvikInsn, calleeMethod,
1557a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng                                     setterInsn.vB, isRange);
1567a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
1577a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    }
1587a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
1597a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    if (dfFlags & DF_UC) {
1607a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng        setterInsn.vC = convertRegId(&invokeMIR->dalvikInsn, calleeMethod,
1617a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng                                     setterInsn.vC, isRange);
1627a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    }
1637a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
1647a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    /* Now setup the Dalvik instruction with converted src/dst registers */
1657a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    newSetterMIR->dalvikInsn = setterInsn;
1667a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
167e485276c6ba778cafa373b3b5c867f84e91b0bfdDan Bornstein    newSetterMIR->width = dexGetWidthFromOpcode(setterInsn.opcode);
1687a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
1697a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    newSetterMIR->OptimizationFlags |= MIR_CALLEE;
1707a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
1717a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    /*
1727a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng     * If the setter instruction is about to raise any exception, punt to the
1737a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng     * interpreter and re-execute the invoke.
1747a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng     */
1757a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    newSetterMIR->offset = invokeMIR->offset;
1767a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
1777a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    newSetterMIR->meta.calleeMethod = calleeMethod;
1787a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
1797a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    dvmCompilerInsertMIRAfter(invokeBB, invokeMIR, newSetterMIR);
1807a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
1817a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    if (isPredicted) {
182fc75f3ed87b55d625b6054e18645da5cbdba31c6Carl Shapiro        MIR *invokeMIRSlow = (MIR *)dvmCompilerNew(sizeof(MIR), true);
1837a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng        *invokeMIRSlow = *invokeMIR;
1845d5b94c8d14b166af580d5dd5906db4f9527d6caCarl Shapiro        invokeMIR->dalvikInsn.opcode = (Opcode)kMirOpCheckInlinePrediction;
1857a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
1867a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng        /* Use vC to denote the first argument (ie this) */
1877a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng        if (!isRange) {
1887a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng            invokeMIR->dalvikInsn.vC = invokeMIRSlow->dalvikInsn.arg[0];
1897a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng        }
1907a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
1917a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng        dvmCompilerInsertMIRAfter(invokeBB, newSetterMIR, invokeMIRSlow);
1927a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng        invokeMIRSlow->OptimizationFlags |= MIR_INLINED_PRED;
1937a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng#if defined(WITH_JIT_TUNING)
1947a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng        gDvmJit.invokePolySetterInlined++;
1957a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng#endif
1967a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    } else {
19733c1cf94f41ee042709e3c7b83f189970a637da2Ben Cheng        /*
19833c1cf94f41ee042709e3c7b83f189970a637da2Ben Cheng         * The invoke becomes no-op so it needs an explicit branch to jump to
19933c1cf94f41ee042709e3c7b83f189970a637da2Ben Cheng         * the chaining cell.
20033c1cf94f41ee042709e3c7b83f189970a637da2Ben Cheng         */
20133c1cf94f41ee042709e3c7b83f189970a637da2Ben Cheng        invokeBB->needFallThroughBranch = true;
2027a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng        invokeMIR->OptimizationFlags |= MIR_INLINED;
2037a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng#if defined(WITH_JIT_TUNING)
2047a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng        gDvmJit.invokeMonoSetterInlined++;
2057a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng#endif
2067a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    }
2077a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
208cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng    return true;
2097a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng}
2107a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
211cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Chengstatic bool tryInlineSingletonCallsite(CompilationUnit *cUnit,
2127a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng                                       const Method *calleeMethod,
2137a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng                                       MIR *invokeMIR,
2147a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng                                       BasicBlock *invokeBB,
2157a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng                                       bool isRange)
2167a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng{
2177a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    /* Not a Java method */
218cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng    if (dvmIsNativeMethod(calleeMethod)) return false;
2197a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
2207a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    CompilerMethodStats *methodStats =
2217a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng        dvmCompilerAnalyzeMethodBody(calleeMethod, true);
2227a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
2237a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    /* Empty callee - do nothing */
2247a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    if (methodStats->attributes & METHOD_IS_EMPTY) {
2257a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng        /* The original invoke instruction is effectively turned into NOP */
2267a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng        invokeMIR->OptimizationFlags |= MIR_INLINED;
22723608ab40900463fc5c8461671ba3aa5d0a4260eBen Cheng        /*
22823608ab40900463fc5c8461671ba3aa5d0a4260eBen Cheng         * Need to insert an explicit branch to catch the falling knife (into
22923608ab40900463fc5c8461671ba3aa5d0a4260eBen Cheng         * the PC reconstruction or chaining cell).
23023608ab40900463fc5c8461671ba3aa5d0a4260eBen Cheng         */
23123608ab40900463fc5c8461671ba3aa5d0a4260eBen Cheng        invokeBB->needFallThroughBranch = true;
232cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng        return true;
2337a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    }
2347a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
2357a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    if (methodStats->attributes & METHOD_IS_GETTER) {
236cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng        return inlineGetter(cUnit, calleeMethod, invokeMIR, invokeBB, false,
237cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng                            isRange);
2387a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    } else if (methodStats->attributes & METHOD_IS_SETTER) {
239cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng        return inlineSetter(cUnit, calleeMethod, invokeMIR, invokeBB, false,
240cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng                            isRange);
2417a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    }
242cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng    return false;
2437a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng}
2447a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
245cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Chengstatic bool inlineEmptyVirtualCallee(CompilationUnit *cUnit,
2467a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng                                     const Method *calleeMethod,
2477a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng                                     MIR *invokeMIR,
2487a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng                                     BasicBlock *invokeBB)
2497a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng{
250fc75f3ed87b55d625b6054e18645da5cbdba31c6Carl Shapiro    MIR *invokeMIRSlow = (MIR *)dvmCompilerNew(sizeof(MIR), true);
2517a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    *invokeMIRSlow = *invokeMIR;
2525d5b94c8d14b166af580d5dd5906db4f9527d6caCarl Shapiro    invokeMIR->dalvikInsn.opcode = (Opcode)kMirOpCheckInlinePrediction;
2537a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
2547a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    dvmCompilerInsertMIRAfter(invokeBB, invokeMIR, invokeMIRSlow);
2557a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    invokeMIRSlow->OptimizationFlags |= MIR_INLINED_PRED;
256cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng    return true;
2577a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng}
2587a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
259cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Chengstatic bool tryInlineVirtualCallsite(CompilationUnit *cUnit,
2607a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng                                     const Method *calleeMethod,
2617a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng                                     MIR *invokeMIR,
2627a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng                                     BasicBlock *invokeBB,
2637a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng                                     bool isRange)
2647a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng{
2657a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    /* Not a Java method */
266cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng    if (dvmIsNativeMethod(calleeMethod)) return false;
2677a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
2687a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    CompilerMethodStats *methodStats =
2697a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng        dvmCompilerAnalyzeMethodBody(calleeMethod, true);
2707a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
2717a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    /* Empty callee - do nothing by checking the clazz pointer */
2727a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    if (methodStats->attributes & METHOD_IS_EMPTY) {
273cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng        return inlineEmptyVirtualCallee(cUnit, calleeMethod, invokeMIR,
274cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng                                        invokeBB);
2757a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    }
2767a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
2777a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    if (methodStats->attributes & METHOD_IS_GETTER) {
278cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng        return inlineGetter(cUnit, calleeMethod, invokeMIR, invokeBB, true,
279cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng                            isRange);
2807a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    } else if (methodStats->attributes & METHOD_IS_SETTER) {
281cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng        return inlineSetter(cUnit, calleeMethod, invokeMIR, invokeBB, true,
282cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng                            isRange);
2837a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    }
284cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng    return false;
2857a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng}
2867a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
2877a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
288cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Chengvoid dvmCompilerInlineMIR(CompilationUnit *cUnit, JitTranslationInfo *info)
2897a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng{
2907a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    bool isRange = false;
29100603079b8723b32c955513eae63a8f97898074dBen Cheng    GrowableListIterator iterator;
2927a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
29300603079b8723b32c955513eae63a8f97898074dBen Cheng    dvmGrowableListIteratorInit(&cUnit->blockList, &iterator);
2947a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    /*
2957a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng     * Analyze the basic block containing an invoke to see if it can be inlined
2967a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng     */
29700603079b8723b32c955513eae63a8f97898074dBen Cheng    while (true) {
29800603079b8723b32c955513eae63a8f97898074dBen Cheng        BasicBlock *bb = (BasicBlock *) dvmGrowableListIteratorNext(&iterator);
29900603079b8723b32c955513eae63a8f97898074dBen Cheng        if (bb == NULL) break;
3007a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng        if (bb->blockType != kDalvikByteCode)
3017a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng            continue;
3027a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng        MIR *lastMIRInsn = bb->lastMIRInsn;
3035d5b94c8d14b166af580d5dd5906db4f9527d6caCarl Shapiro        Opcode opcode = lastMIRInsn->dalvikInsn.opcode;
3045d5b94c8d14b166af580d5dd5906db4f9527d6caCarl Shapiro        int flags = (int)dexGetFlagsFromOpcode(opcode);
3057a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
3067a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng        /* No invoke - continue */
3077a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng        if ((flags & kInstrInvoke) == 0)
3087a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng            continue;
3097a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
31018fba346582c08d81aa96d9508c0e935bad5f36fbuzbee        /* Disable inlining when doing method tracing */
31118fba346582c08d81aa96d9508c0e935bad5f36fbuzbee        if (gDvmJit.methodTraceSupport)
31218fba346582c08d81aa96d9508c0e935bad5f36fbuzbee            continue;
31318fba346582c08d81aa96d9508c0e935bad5f36fbuzbee
3147eb3f7aaf43f07caf0de05ba4ae59e8ea6add796Ben Cheng        /*
3157eb3f7aaf43f07caf0de05ba4ae59e8ea6add796Ben Cheng         * If the invoke itself is selected for single stepping, don't bother
3167eb3f7aaf43f07caf0de05ba4ae59e8ea6add796Ben Cheng         * to inline it.
3177eb3f7aaf43f07caf0de05ba4ae59e8ea6add796Ben Cheng         */
3189a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornstein        if (SINGLE_STEP_OP(opcode))
3197eb3f7aaf43f07caf0de05ba4ae59e8ea6add796Ben Cheng            continue;
3207eb3f7aaf43f07caf0de05ba4ae59e8ea6add796Ben Cheng
3217a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng        const Method *calleeMethod;
3227a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
3239a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornstein        switch (opcode) {
3247a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng            case OP_INVOKE_SUPER:
3257a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng            case OP_INVOKE_DIRECT:
3267a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng            case OP_INVOKE_STATIC:
3277a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng            case OP_INVOKE_SUPER_QUICK:
3287a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng                calleeMethod = lastMIRInsn->meta.callsiteInfo->method;
3297a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng                break;
3307a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng            case OP_INVOKE_SUPER_RANGE:
3317a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng            case OP_INVOKE_DIRECT_RANGE:
3327a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng            case OP_INVOKE_STATIC_RANGE:
3337a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng            case OP_INVOKE_SUPER_QUICK_RANGE:
3347a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng                isRange = true;
3357a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng                calleeMethod = lastMIRInsn->meta.callsiteInfo->method;
3367a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng                break;
3377a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng            default:
3387a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng                calleeMethod = NULL;
3397a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng                break;
3407a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng        }
3417a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
3427a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng        if (calleeMethod) {
343cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng            bool inlined = tryInlineSingletonCallsite(cUnit, calleeMethod,
344cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng                                                      lastMIRInsn, bb, isRange);
345cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng            if (!inlined &&
346cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng                !(gDvmJit.disableOpt & (1 << kMethodJit)) &&
347cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng                !dvmIsNativeMethod(calleeMethod)) {
348cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng                CompilerMethodStats *methodStats =
349cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng                    dvmCompilerAnalyzeMethodBody(calleeMethod, true);
350cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng                if ((methodStats->attributes & METHOD_IS_LEAF) &&
351cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng                    !(methodStats->attributes & METHOD_CANNOT_COMPILE)) {
352cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng                    /* Callee has been previously compiled */
353cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng                    if (dvmJitGetMethodAddr(calleeMethod->insns)) {
354cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng                        lastMIRInsn->OptimizationFlags |= MIR_INVOKE_METHOD_JIT;
355cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng                    } else {
356cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng                        /* Compile the callee first */
357cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng                        dvmCompileMethod(calleeMethod, info);
358cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng                        if (dvmJitGetMethodAddr(calleeMethod->insns)) {
359cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng                            lastMIRInsn->OptimizationFlags |=
360cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng                                MIR_INVOKE_METHOD_JIT;
361cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng                        } else {
362cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng                            methodStats->attributes |= METHOD_CANNOT_COMPILE;
363cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng                        }
364cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng                    }
365cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng                }
366cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng            }
3677a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng            return;
3687a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng        }
3697a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
3709a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornstein        switch (opcode) {
3717a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng            case OP_INVOKE_VIRTUAL:
3727a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng            case OP_INVOKE_VIRTUAL_QUICK:
3737a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng            case OP_INVOKE_INTERFACE:
3747a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng                isRange = false;
3757a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng                calleeMethod = lastMIRInsn->meta.callsiteInfo->method;
3767a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng                break;
3777a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng            case OP_INVOKE_VIRTUAL_RANGE:
3787a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng            case OP_INVOKE_VIRTUAL_QUICK_RANGE:
3797a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng            case OP_INVOKE_INTERFACE_RANGE:
3807a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng                isRange = true;
3817a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng                calleeMethod = lastMIRInsn->meta.callsiteInfo->method;
3827a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng                break;
3837a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng            default:
3847a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng                break;
3857a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng        }
3867a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng
3877a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng        if (calleeMethod) {
388cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng            bool inlined = tryInlineVirtualCallsite(cUnit, calleeMethod,
389cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng                                                    lastMIRInsn, bb, isRange);
390cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng            if (!inlined &&
391cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng                !(gDvmJit.disableOpt & (1 << kMethodJit)) &&
392cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng                !dvmIsNativeMethod(calleeMethod)) {
393cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng                CompilerMethodStats *methodStats =
394cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng                    dvmCompilerAnalyzeMethodBody(calleeMethod, true);
395cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng                if ((methodStats->attributes & METHOD_IS_LEAF) &&
396cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng                    !(methodStats->attributes & METHOD_CANNOT_COMPILE)) {
397cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng                    /* Callee has been previously compiled */
398cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng                    if (dvmJitGetMethodAddr(calleeMethod->insns)) {
399cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng                        lastMIRInsn->OptimizationFlags |= MIR_INVOKE_METHOD_JIT;
400cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng                    } else {
401cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng                        /* Compile the callee first */
402cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng                        dvmCompileMethod(calleeMethod, info);
403cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng                        if (dvmJitGetMethodAddr(calleeMethod->insns)) {
404cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng                            lastMIRInsn->OptimizationFlags |=
405cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng                                MIR_INVOKE_METHOD_JIT;
406cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng                        } else {
407cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng                            methodStats->attributes |= METHOD_CANNOT_COMPILE;
408cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng                        }
409cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng                    }
410cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng                }
411cfdeca37fcaa27c37bad5077223e4d1e87f1182eBen Cheng            }
4127a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng            return;
4137a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng        }
4147a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    }
4157a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng}
416