예제 #1
0
/*
 * Iterate through all successor blocks and propagate up the live-in sets.
 * The calculated result is used for phi-node pruning - where we only need to
 * insert a phi node if the variable is live-in to the block.
 */
static bool computeBlockLiveIns(CompilationUnit *cUnit, BasicBlock *bb) {
    BitVector *tempDalvikRegisterV = cUnit->tempDalvikRegisterV;

    if (bb->dataFlowInfo == NULL) return false;
    dvmCopyBitVector(tempDalvikRegisterV, bb->dataFlowInfo->liveInV);
    if (bb->taken && bb->taken->dataFlowInfo)
        computeSuccLiveIn(tempDalvikRegisterV, bb->taken->dataFlowInfo->liveInV,
                          bb->dataFlowInfo->defV);
    if (bb->fallThrough && bb->fallThrough->dataFlowInfo)
        computeSuccLiveIn(tempDalvikRegisterV,
                          bb->fallThrough->dataFlowInfo->liveInV,
                          bb->dataFlowInfo->defV);
    if (bb->successorBlockList.blockListType != kNotUsed) {
        GrowableListIterator iterator;
        dvmGrowableListIteratorInit(&bb->successorBlockList.blocks,
                                    &iterator);
        while (true) {
            SuccessorBlockInfo *successorBlockInfo =
                    (SuccessorBlockInfo *) dvmGrowableListIteratorNext(&iterator);
            if (successorBlockInfo == NULL) break;
            BasicBlock *succBB = successorBlockInfo->block;
            if (succBB->dataFlowInfo) {
                computeSuccLiveIn(tempDalvikRegisterV,
                                  succBB->dataFlowInfo->liveInV,
                                  bb->dataFlowInfo->defV);
            }
        }
    }
    if (dvmCompareBitVectors(tempDalvikRegisterV, bb->dataFlowInfo->liveInV)) {
        dvmCopyBitVector(bb->dataFlowInfo->liveInV, tempDalvikRegisterV);
        return true;
    }
    return false;
}
예제 #2
0
/* Worker function to compute each block's dominators */
static bool computeBlockDominators(CompilationUnit *cUnit, BasicBlock *bb) {
    GrowableList *blockList = &cUnit->blockList;
    int numTotalBlocks = blockList->numUsed;
    BitVector *tempBlockV = cUnit->tempBlockV;
    BitVectorIterator bvIterator;

    /*
     * The dominator of the entry block has been preset to itself and we need
     * to skip the calculation here.
     */
    if (bb == cUnit->entryBlock) return false;

    dvmSetInitialBits(tempBlockV, numTotalBlocks);

    /* Iterate through the predecessors */
    dvmBitVectorIteratorInit(bb->predecessors, &bvIterator);
    while (true) {
        int predIdx = dvmBitVectorIteratorNext(&bvIterator);
        if (predIdx == -1) break;
        BasicBlock *predBB = (BasicBlock *) dvmGrowableListGetElement(
                blockList, predIdx);
        /* tempBlockV = tempBlockV ^ dominators */
        dvmIntersectBitVectors(tempBlockV, tempBlockV, predBB->dominators);
    }
    dvmSetBit(tempBlockV, bb->id);
    if (dvmCompareBitVectors(tempBlockV, bb->dominators)) {
        dvmCopyBitVector(bb->dominators, tempBlockV);
        return true;
    }
    return false;
}
예제 #3
0
/* Worker function to compute the idom */
static bool computeImmediateDominator(CompilationUnit *cUnit, BasicBlock *bb) {
    GrowableList *blockList = &cUnit->blockList;
    BitVector *tempBlockV = cUnit->tempBlockV;
    BitVectorIterator bvIterator;
    BasicBlock *iDom;

    if (bb == cUnit->entryBlock) return false;

    dvmCopyBitVector(tempBlockV, bb->dominators);
    dvmClearBit(tempBlockV, bb->id);
    dvmBitVectorIteratorInit(tempBlockV, &bvIterator);

    /* Should not see any dead block */
    assert(dvmCountSetBits(tempBlockV) != 0);
    if (dvmCountSetBits(tempBlockV) == 1) {
        iDom = (BasicBlock *) dvmGrowableListGetElement(
                blockList, dvmBitVectorIteratorNext(&bvIterator));
        bb->iDom = iDom;
    } else {
        int iDomIdx = dvmBitVectorIteratorNext(&bvIterator);
        assert(iDomIdx != -1);
        while (true) {
            int nextDom = dvmBitVectorIteratorNext(&bvIterator);
            if (nextDom == -1) break;
            BasicBlock *nextDomBB = (BasicBlock *)
                    dvmGrowableListGetElement(blockList, nextDom);
            /* iDom dominates nextDom - set new iDom */
            if (dvmIsBitSet(nextDomBB->dominators, iDomIdx)) {
                iDomIdx = nextDom;
            }

        }
        iDom = (BasicBlock *) dvmGrowableListGetElement(blockList, iDomIdx);
        /* Set the immediate dominator block for bb */
        bb->iDom = iDom;
    }
    /* Add bb to the iDominated set of the immediate dominator block */
    dvmCompilerSetBit(iDom->iDominated, bb->id);
    return true;
}
예제 #4
0
/*
 * Compute the "liveness" of every register at all GC points.
 */
bool dvmComputeLiveness(VerifierData* vdata)
{
    const InsnFlags* insnFlags = vdata->insnFlags;
    InstructionWidth* backwardWidth;
    VfyBasicBlock* startGuess = NULL;
    BitVector* workBits = NULL;
    bool result = false;

    bool verbose = false; //= dvmWantVerboseVerification(vdata->method);
    if (verbose) {
        const Method* meth = vdata->method;
        ALOGI("Computing liveness for %s.%s:%s",
            meth->clazz->descriptor, meth->name, meth->shorty);
    }

    assert(vdata->registerLines != NULL);

    backwardWidth = createBackwardWidthTable(vdata);
    if (backwardWidth == NULL)
        goto bail;

    /*
     * Allocate space for intra-block work set.  Does not include space
     * for method result "registers", which aren't visible to the GC.
     * (They would be made live by move-result and then die on the
     * instruction immediately before it.)
     */
    workBits = dvmAllocBitVector(vdata->insnRegCount, false);
    if (workBits == NULL)
        goto bail;

    /*
     * We continue until all blocks have been visited, and no block
     * requires further attention ("visited" is set and "changed" is
     * clear).
     *
     * TODO: consider creating a "dense" array of basic blocks to make
     * the walking faster.
     */
    for (int iter = 0;;) {
        VfyBasicBlock* workBlock = NULL;

        if (iter++ > 100000) {
            LOG_VFY_METH(vdata->method, "oh dear");
            dvmAbort();
        }

        /*
         * If a block is marked "changed", we stop and handle it.  If it
         * just hasn't been visited yet, we remember it but keep searching
         * for one that has been changed.
         *
         * The thought here is that this is more likely to let us work
         * from end to start, which reduces the amount of re-evaluation
         * required (both by using "changed" as a work list, and by picking
         * un-visited blocks from the tail end of the method).
         */
        if (startGuess != NULL) {
            assert(startGuess->changed);
            workBlock = startGuess;
        } else {
            for (u4 idx = 0; idx < vdata->insnsSize; idx++) {
                VfyBasicBlock* block = vdata->basicBlocks[idx];
                if (block == NULL)
                    continue;

                if (block->changed) {
                    workBlock = block;
                    break;
                } else if (!block->visited) {
                    workBlock = block;
                }
            }
        }

        if (workBlock == NULL) {
            /* all done */
            break;
        }

        assert(workBlock->changed || !workBlock->visited);
        startGuess = NULL;

        /*
         * Load work bits.  These represent the liveness of registers
         * after the last instruction in the block has finished executing.
         */
        assert(workBlock->liveRegs != NULL);
        dvmCopyBitVector(workBits, workBlock->liveRegs);
        if (verbose) {
            ALOGI("Loaded work bits from last=0x%04x", workBlock->lastAddr);
            dumpLiveState(vdata, 0xfffd, workBlock->liveRegs);
            dumpLiveState(vdata, 0xffff, workBits);
        }

        /*
         * Process a single basic block.
         *
         * If this instruction is a GC point, we want to save the result
         * in the RegisterLine.
         *
         * We don't break basic blocks on every GC point -- in particular,
         * instructions that might throw but have no "try" block don't
         * end a basic block -- so there could be more than one GC point
         * in a given basic block.
         *
         * We could change this, but it turns out to be not all that useful.
         * At first glance it appears that we could share the liveness bit
         * vector between the basic block struct and the register line,
         * but the basic block needs to reflect the state *after* the
         * instruction has finished, while the GC points need to describe
         * the state before the instruction starts.
         */
        u4 curIdx = workBlock->lastAddr;
        while (true) {
            if (!processInstruction(vdata, curIdx, workBits))
                goto bail;

            if (verbose) {
                dumpLiveState(vdata, curIdx + 0x8000, workBits);
            }

            if (dvmInsnIsGcPoint(insnFlags, curIdx)) {
                BitVector* lineBits = vdata->registerLines[curIdx].liveRegs;
                if (lineBits == NULL) {
                    lineBits = vdata->registerLines[curIdx].liveRegs =
                        dvmAllocBitVector(vdata->insnRegCount, false);
                }
                dvmCopyBitVector(lineBits, workBits);
            }

            if (curIdx == workBlock->firstAddr)
                break;
            assert(curIdx >= backwardWidth[curIdx]);
            curIdx -= backwardWidth[curIdx];
        }

        workBlock->visited = true;
        workBlock->changed = false;

        if (verbose) {
            dumpLiveState(vdata, curIdx, workBits);
        }

        /*
         * Merge changes to all predecessors.  If the new bits don't match
         * the old bits, set the "changed" flag.
         */
        PointerSet* preds = workBlock->predecessors;
        size_t numPreds = dvmPointerSetGetCount(preds);
        unsigned int predIdx;

        for (predIdx = 0; predIdx < numPreds; predIdx++) {
            VfyBasicBlock* pred =
                    (VfyBasicBlock*) dvmPointerSetGetEntry(preds, predIdx);

            pred->changed = dvmCheckMergeBitVectors(pred->liveRegs, workBits);
            if (verbose) {
                ALOGI("merging cur=%04x into pred last=%04x (ch=%d)",
                    curIdx, pred->lastAddr, pred->changed);
                dumpLiveState(vdata, 0xfffa, pred->liveRegs);
                dumpLiveState(vdata, 0xfffb, workBits);
            }

            /*
             * We want to set the "changed" flag on unvisited predecessors
             * as a way of guiding the verifier through basic blocks in
             * a reasonable order.  We can't count on variable liveness
             * changing, so we force "changed" to true even if it hasn't.
             */
            if (!pred->visited)
                pred->changed = true;

            /*
             * Keep track of one of the changed blocks so we can start
             * there instead of having to scan through the list.
             */
            if (pred->changed)
                startGuess = pred;
        }
    }

#ifndef NDEBUG
    /*
     * Sanity check: verify that all GC point register lines have a
     * liveness bit vector allocated.  Also, we're not expecting non-GC
     * points to have them.
     */
    u4 checkIdx;
    for (checkIdx = 0; checkIdx < vdata->insnsSize; ) {
        if (dvmInsnIsGcPoint(insnFlags, checkIdx)) {
            if (vdata->registerLines[checkIdx].liveRegs == NULL) {
                LOG_VFY_METH(vdata->method,
                    "GLITCH: no liveRegs for GC point 0x%04x", checkIdx);
                dvmAbort();
            }
        } else if (vdata->registerLines[checkIdx].liveRegs != NULL) {
            LOG_VFY_METH(vdata->method,
                "GLITCH: liveRegs for non-GC point 0x%04x", checkIdx);
            dvmAbort();
        }
        u4 insnWidth = dvmInsnGetWidth(insnFlags, checkIdx);
        checkIdx += insnWidth;
    }
#endif

    /*
     * Factor in the debug info, if any.
     */
    if (!markDebugLocals(vdata))
        goto bail;

    result = true;

bail:
    free(backwardWidth);
    dvmFreeBitVector(workBits);
    return result;
}
예제 #5
0
/* Insert phi nodes to for each variable to the dominance frontiers */
static void insertPhiNodes(CompilationUnit *cUnit) {
    int dalvikReg;
    const GrowableList *blockList = &cUnit->blockList;
    BitVector *phiBlocks =
            dvmCompilerAllocBitVector(cUnit->numBlocks, false);
    BitVector *tmpBlocks =
            dvmCompilerAllocBitVector(cUnit->numBlocks, false);
    BitVector *inputBlocks =
            dvmCompilerAllocBitVector(cUnit->numBlocks, false);

    cUnit->tempDalvikRegisterV =
            dvmCompilerAllocBitVector(cUnit->numDalvikRegisters, false);

    dvmCompilerDataFlowAnalysisDispatcher(cUnit, computeBlockLiveIns,
                                          kPostOrderDFSTraversal,
                                          true /* isIterative */);

    /* Iterate through each Dalvik register */
    for (dalvikReg = 0; dalvikReg < cUnit->numDalvikRegisters; dalvikReg++) {
        bool change;
        BitVectorIterator iterator;

        dvmCopyBitVector(inputBlocks, cUnit->defBlockMatrix[dalvikReg]);
        dvmClearAllBits(phiBlocks);

        /* Calculate the phi blocks for each Dalvik register */
        do {
            change = false;
            dvmClearAllBits(tmpBlocks);
            dvmBitVectorIteratorInit(inputBlocks, &iterator);

            while (true) {
                int idx = dvmBitVectorIteratorNext(&iterator);
                if (idx == -1) break;
                BasicBlock *defBB =
                        (BasicBlock *) dvmGrowableListGetElement(blockList, idx);

                /* Merge the dominance frontier to tmpBlocks */
                dvmUnifyBitVectors(tmpBlocks, tmpBlocks, defBB->domFrontier);
            }
            if (dvmCompareBitVectors(phiBlocks, tmpBlocks)) {
                change = true;
                dvmCopyBitVector(phiBlocks, tmpBlocks);

                /*
                 * Iterate through the original blocks plus the new ones in
                 * the dominance frontier.
                 */
                dvmCopyBitVector(inputBlocks, phiBlocks);
                dvmUnifyBitVectors(inputBlocks, inputBlocks,
                                   cUnit->defBlockMatrix[dalvikReg]);
            }
        } while (change);

        /*
         * Insert a phi node for dalvikReg in the phiBlocks if the Dalvik
         * register is in the live-in set.
         */
        dvmBitVectorIteratorInit(phiBlocks, &iterator);
        while (true) {
            int idx = dvmBitVectorIteratorNext(&iterator);
            if (idx == -1) break;
            BasicBlock *phiBB =
                    (BasicBlock *) dvmGrowableListGetElement(blockList, idx);
            /* Variable will be clobbered before being used - no need for phi */
            if (!dvmIsBitSet(phiBB->dataFlowInfo->liveInV, dalvikReg)) continue;
            MIR *phi = (MIR *) dvmCompilerNew(sizeof(MIR), true);
            phi->dalvikInsn.opcode = (Opcode) kMirOpPhi;
            phi->dalvikInsn.vA = dalvikReg;
            phi->offset = phiBB->startOffset;
            dvmCompilerPrependMIR(phiBB, phi);
        }
    }
}