/** * Inserts mark-locals if necessary when changing a register. If the definition of {@code origReg} * is associated with a local variable, then insert a mark-local for {@code newReg} just below it. * We expect the definition of {@code origReg} to ultimately be removed by the dead code * eliminator * * @param origReg {@code non-null;} original register * @param newReg {@code non-null;} new register that will replace {@code origReg} */ private void fixLocalAssignment(RegisterSpec origReg, RegisterSpec newReg) { for (SsaInsn use : ssaMeth.getUseListForRegister(origReg.getReg())) { RegisterSpec localAssignment = use.getLocalAssignment(); if (localAssignment == null) { continue; } if (use.getResult() == null) { /* * This is a mark-local. it will be updated when all uses are * updated. */ continue; } LocalItem local = localAssignment.getLocalItem(); // Un-associate original use. use.setResultLocal(null); // Now add a mark-local to the new reg immediately after. newReg = newReg.withLocalItem(local); SsaInsn newInsn = SsaInsn.makeFromRop( new PlainInsn( Rops.opMarkLocal(newReg), SourcePosition.NO_INFO, null, RegisterSpecList.make(newReg)), use.getBlock()); ArrayList<SsaInsn> insns = use.getBlock().getInsns(); insns.add(insns.indexOf(use) + 1, newInsn); } }
/** * Processes a single block. * * @param blockIndex {@code >= 0;} block index of the block to process */ private void processBlock(int blockIndex) { RegisterSpecSet primaryState = resultInfo.mutableCopyOfStarts(blockIndex); SsaBasicBlock block = blocks.get(blockIndex); List<SsaInsn> insns = block.getInsns(); int insnSz = insns.size(); // The exit block has no insns and no successors if (blockIndex == method.getExitBlockIndex()) { return; } /* * We may have to treat the last instruction specially: If it * can (but doesn't always) throw, and the exception can be * caught within the same method, then we need to use the * state *before* executing it to be what is merged into * exception targets. */ SsaInsn lastInsn = insns.get(insnSz - 1); boolean hasExceptionHandlers = lastInsn.getOriginalRopInsn().getCatches().size() != 0; boolean canThrowDuringLastInsn = hasExceptionHandlers && (lastInsn.getResult() != null); int freezeSecondaryStateAt = insnSz - 1; RegisterSpecSet secondaryState = primaryState; /* * Iterate over the instructions, adding information for each place * that the active variable set changes. */ for (int i = 0; i < insnSz; i++) { if (canThrowDuringLastInsn && (i == freezeSecondaryStateAt)) { // Until this point, primaryState == secondaryState. primaryState.setImmutable(); primaryState = primaryState.mutableCopy(); } SsaInsn insn = insns.get(i); RegisterSpec result; result = insn.getLocalAssignment(); if (result == null) { // We may be nuking an existing local result = insn.getResult(); if (result != null && primaryState.get(result.getReg()) != null) { primaryState.remove(primaryState.get(result.getReg())); } continue; } result = result.withSimpleType(); RegisterSpec already = primaryState.get(result); /* * The equals() check ensures we only add new info if * the instruction causes a change to the set of * active variables. */ if (!result.equals(already)) { /* * If this insn represents a local moving from one register * to another, remove the association between the old register * and the local. */ RegisterSpec previous = primaryState.localItemToSpec(result.getLocalItem()); if (previous != null && (previous.getReg() != result.getReg())) { primaryState.remove(previous); } resultInfo.addAssignment(insn, result); primaryState.put(result); } } primaryState.setImmutable(); /* * Merge this state into the start state for each successor, * and update the work set where required (that is, in cases * where the start state for a block changes). */ IntList successors = block.getSuccessorList(); int succSz = successors.size(); int primarySuccessor = block.getPrimarySuccessorIndex(); for (int i = 0; i < succSz; i++) { int succ = successors.get(i); RegisterSpecSet state = (succ == primarySuccessor) ? primaryState : secondaryState; if (resultInfo.mergeStarts(succ, state)) { workSet.set(succ); } } }