Home | History | Annotate | Download | only in back
      1 /*
      2  * Copyright (C) 2007 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 package com.android.dx.ssa.back;
     18 
     19 import com.android.dx.rop.code.*;
     20 import com.android.dx.rop.cst.CstInteger;
     21 import com.android.dx.ssa.InterferenceRegisterMapper;
     22 import com.android.dx.ssa.RegisterMapper;
     23 import com.android.dx.ssa.SsaInsn;
     24 import com.android.dx.ssa.SsaMethod;
     25 import com.android.dx.ssa.NormalSsaInsn;
     26 import com.android.dx.ssa.PhiInsn;
     27 import com.android.dx.ssa.Optimizer;
     28 import com.android.dx.ssa.SsaBasicBlock;
     29 import com.android.dx.util.IntSet;
     30 import com.android.dx.util.IntIterator;
     31 
     32 import java.util.ArrayList;
     33 import java.util.BitSet;
     34 import java.util.Map;
     35 import java.util.TreeMap;
     36 
     37 /**
     38  * Allocates registers in a first-fit fashion, with the bottom reserved for
     39  * method parameters and all SSAregisters representing the same local variable
     40  * kept together if possible.
     41  */
     42 public class FirstFitLocalCombiningAllocator extends RegisterAllocator {
     43     /** local debug flag */
     44     private static final boolean DEBUG = false;
     45 
     46     /** maps local variable to a list of associated SSA registers */
     47     private final Map<LocalItem, ArrayList<RegisterSpec>> localVariables;
     48 
     49     /** list of move-result-pesudo instructions seen in this method */
     50     private final ArrayList<NormalSsaInsn> moveResultPseudoInsns;
     51 
     52     /** list of invoke-range instructions seen in this method */
     53     private final ArrayList<NormalSsaInsn> invokeRangeInsns;
     54 
     55     /** list of phi instructions seen in this method */
     56     private final ArrayList<PhiInsn> phiInsns;
     57 
     58     /** indexed by SSA reg; the set of SSA regs we've mapped */
     59     private final BitSet ssaRegsMapped;
     60 
     61     /** Register mapper which will be our result */
     62     private final InterferenceRegisterMapper mapper;
     63 
     64     /** end of rop registers range (starting at 0) reserved for parameters */
     65     private final int paramRangeEnd;
     66 
     67     /** set of rop registers reserved for parameters or local variables */
     68     private final BitSet reservedRopRegs;
     69 
     70     /** set of rop registers that have been used by anything */
     71     private final BitSet usedRopRegs;
     72 
     73     /** true if converter should take steps to minimize rop-form registers */
     74     private final boolean minimizeRegisters;
     75 
     76     /**
     77      * Constructs instance.
     78      *
     79      * @param ssaMeth {@code non-null;} method to process
     80      * @param interference non-null interference graph for SSA registers
     81      * @param minimizeRegisters true if converter should take steps to
     82      * minimize rop-form registers
     83      */
     84     public FirstFitLocalCombiningAllocator(
     85             SsaMethod ssaMeth, InterferenceGraph interference,
     86             boolean minimizeRegisters) {
     87         super(ssaMeth, interference);
     88 
     89         ssaRegsMapped = new BitSet(ssaMeth.getRegCount());
     90 
     91         mapper = new InterferenceRegisterMapper(
     92                 interference, ssaMeth.getRegCount());
     93 
     94         this.minimizeRegisters = minimizeRegisters;
     95 
     96         /*
     97          * Reserve space for the params at the bottom of the register
     98          * space. Later, we'll flip the params to the end of the register
     99          * space.
    100          */
    101 
    102         paramRangeEnd = ssaMeth.getParamWidth();
    103 
    104         reservedRopRegs = new BitSet(paramRangeEnd * 2);
    105         reservedRopRegs.set(0, paramRangeEnd);
    106         usedRopRegs = new BitSet(paramRangeEnd * 2);
    107         localVariables = new TreeMap<LocalItem, ArrayList<RegisterSpec>>();
    108         moveResultPseudoInsns = new ArrayList<NormalSsaInsn>();
    109         invokeRangeInsns = new ArrayList<NormalSsaInsn>();
    110         phiInsns = new ArrayList<PhiInsn>();
    111     }
    112 
    113     /** {@inheritDoc} */
    114     @Override
    115     public boolean wantsParamsMovedHigh() {
    116         return true;
    117     }
    118 
    119     /** {@inheritDoc} */
    120     @Override
    121     public RegisterMapper allocateRegisters() {
    122 
    123         analyzeInstructions();
    124 
    125         if (DEBUG) {
    126             printLocalVars();
    127         }
    128 
    129         if (DEBUG) System.out.println("--->Mapping local-associated params");
    130         handleLocalAssociatedParams();
    131 
    132         if (DEBUG) System.out.println("--->Mapping other params");
    133         handleUnassociatedParameters();
    134 
    135         if (DEBUG) System.out.println("--->Mapping invoke-range");
    136         handleInvokeRangeInsns();
    137 
    138         if (DEBUG) {
    139             System.out.println("--->Mapping local-associated non-params");
    140         }
    141         handleLocalAssociatedOther();
    142 
    143         if (DEBUG) System.out.println("--->Mapping check-cast results");
    144         handleCheckCastResults();
    145 
    146         if (DEBUG) System.out.println("--->Mapping phis");
    147         handlePhiInsns();
    148 
    149         if (DEBUG) System.out.println("--->Mapping others");
    150         handleNormalUnassociated();
    151 
    152         return mapper;
    153     }
    154 
    155     /**
    156      * Dumps local variable table to stdout for debugging.
    157      */
    158     private void printLocalVars() {
    159         System.out.println("Printing local vars");
    160         for (Map.Entry<LocalItem, ArrayList<RegisterSpec>> e :
    161                 localVariables.entrySet()) {
    162             StringBuilder regs = new StringBuilder();
    163 
    164             regs.append('{');
    165             regs.append(' ');
    166             for (RegisterSpec reg : e.getValue()) {
    167                 regs.append('v');
    168                 regs.append(reg.getReg());
    169                 regs.append(' ');
    170             }
    171             regs.append('}');
    172             System.out.printf("Local: %s Registers: %s\n", e.getKey(), regs);
    173         }
    174     }
    175 
    176     /**
    177      * Maps all local-associated parameters to rop registers.
    178      */
    179     private void handleLocalAssociatedParams() {
    180         for (ArrayList<RegisterSpec> ssaRegs : localVariables.values()) {
    181             int sz = ssaRegs.size();
    182             int paramIndex = -1;
    183             int paramCategory = 0;
    184 
    185             // First, find out if this local variable is a parameter.
    186             for (int i = 0; i < sz; i++) {
    187                 RegisterSpec ssaSpec = ssaRegs.get(i);
    188                 int ssaReg = ssaSpec.getReg();
    189 
    190                 paramIndex = getParameterIndexForReg(ssaReg);
    191 
    192                 if (paramIndex >= 0) {
    193                     paramCategory = ssaSpec.getCategory();
    194                     addMapping(ssaSpec, paramIndex);
    195                     break;
    196                 }
    197             }
    198 
    199             if (paramIndex < 0) {
    200                 // This local wasn't a parameter.
    201                 continue;
    202             }
    203 
    204             // Any remaining local-associated registers will be mapped later.
    205             tryMapRegs(ssaRegs, paramIndex, paramCategory, true);
    206         }
    207     }
    208 
    209     /**
    210      * Gets the parameter index for SSA registers that are method parameters.
    211      * {@code -1} is returned for non-parameter registers.
    212      *
    213      * @param ssaReg {@code >=0;} SSA register to look up
    214      * @return parameter index or {@code -1} if not a parameter
    215      */
    216     private int getParameterIndexForReg(int ssaReg) {
    217         SsaInsn defInsn = ssaMeth.getDefinitionForRegister(ssaReg);
    218         if (defInsn == null) {
    219             return -1;
    220         }
    221 
    222         Rop opcode = defInsn.getOpcode();
    223 
    224         // opcode == null for phi insns.
    225         if (opcode != null && opcode.getOpcode() == RegOps.MOVE_PARAM) {
    226             CstInsn origInsn = (CstInsn) defInsn.getOriginalRopInsn();
    227             return  ((CstInteger) origInsn.getConstant()).getValue();
    228         }
    229 
    230         return -1;
    231     }
    232 
    233     /**
    234      * Maps all local-associated registers that are not parameters.
    235      * Tries to find an unreserved range that's wide enough for all of
    236      * the SSA registers, and then tries to map them all to that
    237      * range. If not all fit, a new range is tried until all registers
    238      * have been fit.
    239      */
    240     private void handleLocalAssociatedOther() {
    241         for (ArrayList<RegisterSpec> specs : localVariables.values()) {
    242             int ropReg = paramRangeEnd;
    243 
    244             boolean done = false;
    245             do {
    246                 int maxCategory = 1;
    247 
    248                 // Compute max category for remaining unmapped registers.
    249                 int sz = specs.size();
    250                 for (int i = 0; i < sz; i++) {
    251                     RegisterSpec ssaSpec = specs.get(i);
    252                     int category = ssaSpec.getCategory();
    253                     if (!ssaRegsMapped.get(ssaSpec.getReg())
    254                             && category > maxCategory) {
    255                         maxCategory = category;
    256                     }
    257                 }
    258 
    259                 ropReg = findRopRegForLocal(ropReg, maxCategory);
    260                 if (canMapRegs(specs, ropReg)) {
    261                     done = tryMapRegs(specs, ropReg, maxCategory, true);
    262                 }
    263 
    264                 // Increment for next call to findRopRegForLocal.
    265                 ropReg++;
    266             } while (!done);
    267         }
    268     }
    269 
    270     /**
    271      * Tries to map a list of SSA registers into the a rop reg, marking
    272      * used rop space as reserved. SSA registers that don't fit are left
    273      * unmapped.
    274      *
    275      * @param specs {@code non-null;} SSA registers to attempt to map
    276      * @param ropReg {@code >=0;} rop register to map to
    277      * @param maxAllowedCategory {@code 1..2;} maximum category
    278      * allowed in mapping.
    279      * @param markReserved do so if {@code true}
    280      * @return {@code true} if all registers were mapped, {@code false}
    281      * if some remain unmapped
    282      */
    283     private boolean tryMapRegs(
    284             ArrayList<RegisterSpec> specs, int ropReg,
    285             int maxAllowedCategory, boolean markReserved) {
    286         boolean remaining = false;
    287         for (RegisterSpec spec : specs) {
    288             if (ssaRegsMapped.get(spec.getReg())) {
    289                 continue;
    290             }
    291 
    292             boolean succeeded;
    293             succeeded = tryMapReg(spec, ropReg, maxAllowedCategory);
    294             remaining = !succeeded || remaining;
    295             if (succeeded && markReserved) {
    296                 // This only needs to be called once really with
    297                 // the widest category used, but <shrug>
    298                 markReserved(ropReg, spec.getCategory());
    299             }
    300         }
    301         return !remaining;
    302     }
    303 
    304     /**
    305      * Tries to map an SSA register to a rop register.
    306      *
    307      * @param ssaSpec {@code non-null;} SSA register
    308      * @param ropReg {@code >=0;} rop register
    309      * @param maxAllowedCategory {@code 1..2;} the maximum category
    310      * that the SSA register is allowed to be
    311      * @return {@code true} if map succeeded, {@code false} if not
    312      */
    313     private boolean tryMapReg(RegisterSpec ssaSpec, int ropReg,
    314             int maxAllowedCategory) {
    315         if (ssaSpec.getCategory() <= maxAllowedCategory
    316                 && !ssaRegsMapped.get(ssaSpec.getReg())
    317                 && canMapReg(ssaSpec, ropReg)) {
    318             addMapping(ssaSpec, ropReg);
    319             return true;
    320         }
    321 
    322         return false;
    323     }
    324 
    325     /**
    326      * Marks a range of rop registers as "reserved for a local variable."
    327      *
    328      * @param ropReg {@code >= 0;} rop register to reserve
    329      * @param category {@code > 0;} width to reserve
    330      */
    331     private void markReserved(int ropReg, int category) {
    332         reservedRopRegs.set(ropReg, ropReg + category, true);
    333     }
    334 
    335     /**
    336      * Checks to see if any rop registers in the specified range are reserved
    337      * for local variables or parameters.
    338      *
    339      * @param ropRangeStart {@code >= 0;} lowest rop register
    340      * @param width {@code > 0;} number of rop registers in range.
    341      * @return {@code true} if any register in range is marked reserved
    342      */
    343     private boolean rangeContainsReserved(int ropRangeStart, int width) {
    344         for (int i = ropRangeStart; i < (ropRangeStart + width); i++) {
    345             if (reservedRopRegs.get(i)) {
    346                 return true;
    347             }
    348         }
    349         return false;
    350     }
    351 
    352     /**
    353      * Returns true if given rop register represents the {@code this} pointer
    354      * for a non-static method.
    355      *
    356      * @param startReg rop register
    357      * @return true if the "this" pointer is located here.
    358      */
    359     private boolean isThisPointerReg(int startReg) {
    360         // "this" is always the first parameter.
    361         return startReg == 0 && !ssaMeth.isStatic();
    362     }
    363 
    364     /**
    365      * Finds a range of unreserved rop registers.
    366      *
    367      * @param startReg {@code >= 0;} a rop register to start the search at
    368      * @param width {@code > 0;} the width, in registers, required.
    369      * @return {@code >= 0;} start of available register range.
    370      */
    371     private int findNextUnreservedRopReg(int startReg, int width) {
    372         int reg;
    373 
    374         reg = reservedRopRegs.nextClearBit(startReg);
    375 
    376         while (true) {
    377             int i = 1;
    378 
    379             while (i < width && !reservedRopRegs.get(reg + i)) {
    380                 i++;
    381             }
    382 
    383             if (i == width) {
    384                 return reg;
    385             }
    386 
    387             reg = reservedRopRegs.nextClearBit(reg + i);
    388         }
    389     }
    390 
    391     /**
    392      * Finds a range of rop regs that can be used for local variables.
    393      * If {@code MIX_LOCALS_AND_OTHER} is {@code false}, this means any
    394      * rop register that has not yet been used.
    395      *
    396      * @param startReg {@code >= 0;} a rop register to start the search at
    397      * @param width {@code > 0;} the width, in registers, required.
    398      * @return {@code >= 0;} start of available register range.
    399      */
    400     private int findRopRegForLocal(int startReg, int width) {
    401         int reg;
    402 
    403         reg = usedRopRegs.nextClearBit(startReg);
    404 
    405         while (true) {
    406             int i = 1;
    407 
    408             while (i < width && !usedRopRegs.get(reg + i)) {
    409                 i++;
    410             }
    411 
    412             if (i == width) {
    413                 return reg;
    414             }
    415 
    416             reg = usedRopRegs.nextClearBit(reg + i);
    417         }
    418     }
    419 
    420     /**
    421      * Maps any parameter that isn't local-associated, which can happen
    422      * in the case where there is no java debug info.
    423      */
    424     private void handleUnassociatedParameters() {
    425         int szSsaRegs = ssaMeth.getRegCount();
    426 
    427         for (int ssaReg = 0; ssaReg < szSsaRegs; ssaReg++) {
    428             if (ssaRegsMapped.get(ssaReg)) {
    429                 // We already did this one above
    430                 continue;
    431             }
    432 
    433             int paramIndex = getParameterIndexForReg(ssaReg);
    434 
    435             RegisterSpec ssaSpec = getDefinitionSpecForSsaReg(ssaReg);
    436             if (paramIndex >= 0) {
    437                 addMapping(ssaSpec, paramIndex);
    438             }
    439         }
    440     }
    441 
    442     /**
    443      * Handles all insns that want a register range for their sources.
    444      */
    445     private void handleInvokeRangeInsns() {
    446         for (NormalSsaInsn insn : invokeRangeInsns) {
    447             adjustAndMapSourceRangeRange(insn);
    448         }
    449     }
    450 
    451     /**
    452      * Handles check cast results to reuse the same source register.
    453      * Inserts a move if it can't map the same register to both and the
    454      * check cast is not caught.
    455      */
    456     private void handleCheckCastResults() {
    457         for (NormalSsaInsn insn : moveResultPseudoInsns) {
    458             RegisterSpec moveRegSpec = insn.getResult();
    459             int moveReg = moveRegSpec.getReg();
    460             BitSet predBlocks = insn.getBlock().getPredecessors();
    461 
    462             // Expect one predecessor block only
    463             if (predBlocks.cardinality() != 1) {
    464                 continue;
    465             }
    466 
    467             SsaBasicBlock predBlock =
    468                     ssaMeth.getBlocks().get(predBlocks.nextSetBit(0));
    469             ArrayList<SsaInsn> insnList = predBlock.getInsns();
    470 
    471             /**
    472              * If the predecessor block has a check-cast, it will be the last
    473              * instruction
    474              */
    475             SsaInsn checkCastInsn = insnList.get(insnList.size() - 1);
    476             if (checkCastInsn.getOpcode().getOpcode() != RegOps.CHECK_CAST) {
    477                 continue;
    478             }
    479 
    480             RegisterSpec checkRegSpec = checkCastInsn.getSources().get(0);
    481             int checkReg = checkRegSpec.getReg();
    482 
    483             /**
    484              * See if either register is already mapped. Most likely the move
    485              * result will be mapped already since the cast result is stored
    486              * in a local variable.
    487              */
    488             int category = checkRegSpec.getCategory();
    489             boolean moveMapped = ssaRegsMapped.get(moveReg);
    490             boolean checkMapped = ssaRegsMapped.get(checkReg);
    491             if (moveMapped & !checkMapped) {
    492                 int moveRopReg = mapper.oldToNew(moveReg);
    493                 checkMapped = tryMapReg(checkRegSpec, moveRopReg, category);
    494             }
    495             if (checkMapped & !moveMapped) {
    496                 int checkRopReg = mapper.oldToNew(checkReg);
    497                 moveMapped = tryMapReg(moveRegSpec, checkRopReg, category);
    498             }
    499 
    500             // Map any unmapped registers to anything available
    501             if (!moveMapped || !checkMapped) {
    502                 int ropReg = findNextUnreservedRopReg(paramRangeEnd, category);
    503                 ArrayList<RegisterSpec> ssaRegs =
    504                     new ArrayList<RegisterSpec>(2);
    505                 ssaRegs.add(moveRegSpec);
    506                 ssaRegs.add(checkRegSpec);
    507 
    508                 while (!tryMapRegs(ssaRegs, ropReg, category, false)) {
    509                     ropReg = findNextUnreservedRopReg(ropReg + 1, category);
    510                 }
    511             }
    512 
    513             /*
    514              * If source and result have a different mapping, insert a move so
    515              * they can have the same mapping. Don't do this if the check cast
    516              * is caught, since it will overwrite a potentially live value.
    517              */
    518             boolean hasExceptionHandlers =
    519                 checkCastInsn.getOriginalRopInsn().getCatches().size() != 0;
    520             int moveRopReg = mapper.oldToNew(moveReg);
    521             int checkRopReg = mapper.oldToNew(checkReg);
    522             if (moveRopReg != checkRopReg && !hasExceptionHandlers) {
    523                 ((NormalSsaInsn) checkCastInsn).changeOneSource(0,
    524                         insertMoveBefore(checkCastInsn, checkRegSpec));
    525                 addMapping(checkCastInsn.getSources().get(0), moveRopReg);
    526             }
    527         }
    528     }
    529 
    530     /**
    531     * Handles all phi instructions, trying to map them to a common register.
    532     */
    533     private void handlePhiInsns() {
    534         for (PhiInsn insn : phiInsns) {
    535             processPhiInsn(insn);
    536         }
    537     }
    538 
    539     /**
    540      * Maps all non-parameter, non-local variable registers.
    541      */
    542     private void handleNormalUnassociated() {
    543         int szSsaRegs = ssaMeth.getRegCount();
    544 
    545         for (int ssaReg = 0; ssaReg < szSsaRegs; ssaReg++) {
    546             if (ssaRegsMapped.get(ssaReg)) {
    547                 // We already did this one
    548                 continue;
    549             }
    550 
    551             RegisterSpec ssaSpec = getDefinitionSpecForSsaReg(ssaReg);
    552 
    553             if (ssaSpec == null) continue;
    554 
    555             int category = ssaSpec.getCategory();
    556             // Find a rop reg that does not interfere
    557             int ropReg = findNextUnreservedRopReg(paramRangeEnd, category);
    558             while (!canMapReg(ssaSpec, ropReg)) {
    559                 ropReg = findNextUnreservedRopReg(ropReg + 1, category);
    560             }
    561 
    562             addMapping(ssaSpec, ropReg);
    563         }
    564     }
    565 
    566     /**
    567      * Checks to see if a list of SSA registers can all be mapped into
    568      * the same rop reg. Ignores registers that have already been mapped,
    569      * and checks the interference graph and ensures the range does not
    570      * cross the parameter range.
    571      *
    572      * @param specs {@code non-null;} SSA registers to check
    573      * @param ropReg {@code >=0;} rop register to check mapping to
    574      * @return {@code true} if all unmapped registers can be mapped
    575      */
    576     private boolean canMapRegs(ArrayList<RegisterSpec> specs, int ropReg) {
    577         for (RegisterSpec spec : specs) {
    578             if (ssaRegsMapped.get(spec.getReg())) continue;
    579             if (!canMapReg(spec, ropReg)) return false;
    580         }
    581         return true;
    582     }
    583 
    584     /**
    585      * Checks to see if {@code ssaSpec} can be mapped to
    586      * {@code ropReg}. Checks interference graph and ensures
    587      * the range does not cross the parameter range.
    588      *
    589      * @param ssaSpec {@code non-null;} SSA spec
    590      * @param ropReg prosepctive new-namespace reg
    591      * @return {@code true} if mapping is possible
    592      */
    593     private boolean canMapReg(RegisterSpec ssaSpec, int ropReg) {
    594         int category = ssaSpec.getCategory();
    595         return !(spansParamRange(ropReg, category)
    596                 || mapper.interferes(ssaSpec, ropReg));
    597     }
    598 
    599     /**
    600      * Returns true if the specified rop register + category
    601      * will cross the boundry between the lower {@code paramWidth}
    602      * registers reserved for method params and the upper registers. We cannot
    603      * allocate a register that spans the param block and the normal block,
    604      * because we will be moving the param block to high registers later.
    605      *
    606      * @param ssaReg register in new namespace
    607      * @param category width that the register will have
    608      * @return {@code true} in the case noted above
    609      */
    610     private boolean spansParamRange(int ssaReg, int category) {
    611         return ((ssaReg < paramRangeEnd)
    612                 && ((ssaReg + category) > paramRangeEnd));
    613     }
    614 
    615     /**
    616      * Analyze each instruction and find out all the local variable assignments
    617      * and move-result-pseudo/invoke-range instrucitons.
    618      */
    619     private void analyzeInstructions() {
    620         ssaMeth.forEachInsn(new SsaInsn.Visitor() {
    621             /** {@inheritDoc} */
    622             public void visitMoveInsn(NormalSsaInsn insn) {
    623                 processInsn(insn);
    624             }
    625 
    626             /** {@inheritDoc} */
    627             public void visitPhiInsn(PhiInsn insn) {
    628                 processInsn(insn);
    629             }
    630 
    631             /** {@inheritDoc} */
    632             public void visitNonMoveInsn(NormalSsaInsn insn) {
    633                 processInsn(insn);
    634             }
    635 
    636             /**
    637              * This method collects three types of instructions:
    638              *
    639              * 1) Adds a local variable assignment to the
    640              *    {@code localVariables} map.
    641              * 2) Add move-result-pseudo to the
    642              *    {@code moveResultPseudoInsns} list.
    643              * 3) Add invoke-range to the
    644              *    {@code invokeRangeInsns} list.
    645              *
    646              * @param insn {@code non-null;} insn that may represent a
    647              * local variable assignment
    648              */
    649             private void processInsn(SsaInsn insn) {
    650                 RegisterSpec assignment;
    651                 assignment = insn.getLocalAssignment();
    652 
    653                 if (assignment != null) {
    654                     LocalItem local = assignment.getLocalItem();
    655 
    656                     ArrayList<RegisterSpec> regList
    657                         = localVariables.get(local);
    658 
    659                     if (regList == null) {
    660                         regList = new ArrayList<RegisterSpec>();
    661                         localVariables.put(local, regList);
    662                     }
    663 
    664                     regList.add(assignment);
    665                 }
    666 
    667                 if (insn instanceof NormalSsaInsn) {
    668                     if (insn.getOpcode().getOpcode() ==
    669                             RegOps.MOVE_RESULT_PSEUDO) {
    670                         moveResultPseudoInsns.add((NormalSsaInsn) insn);
    671                     } else if (Optimizer.getAdvice().requiresSourcesInOrder(
    672                             insn.getOriginalRopInsn().getOpcode(),
    673                             insn.getSources())) {
    674                         invokeRangeInsns.add((NormalSsaInsn) insn);
    675                     }
    676                 } else if (insn instanceof PhiInsn) {
    677                     phiInsns.add((PhiInsn) insn);
    678                 }
    679 
    680             }
    681         });
    682     }
    683 
    684     /**
    685      * Adds a mapping from an SSA register to a rop register.
    686      * {@link #canMapReg} should have already been called.
    687      *
    688      * @param ssaSpec {@code non-null;} SSA register to map from
    689      * @param ropReg {@code >=0;} rop register to map to
    690      */
    691     private void addMapping(RegisterSpec ssaSpec, int ropReg) {
    692         int ssaReg = ssaSpec.getReg();
    693 
    694         // An assertion.
    695         if (ssaRegsMapped.get(ssaReg) || !canMapReg(ssaSpec, ropReg)) {
    696             throw new RuntimeException(
    697                     "attempt to add invalid register mapping");
    698         }
    699 
    700         if (DEBUG) {
    701             System.out.printf("Add mapping s%d -> v%d c:%d\n",
    702                     ssaSpec.getReg(), ropReg, ssaSpec.getCategory());
    703         }
    704 
    705         int category = ssaSpec.getCategory();
    706         mapper.addMapping(ssaSpec.getReg(), ropReg, category);
    707         ssaRegsMapped.set(ssaReg);
    708         usedRopRegs.set(ropReg, ropReg + category);
    709     }
    710 
    711 
    712     /**
    713      * Maps the source registers of the specified instruction such that they
    714      * will fall in a contiguous range in rop form. Moves are inserted as
    715      * necessary to allow the range to be allocated.
    716      *
    717      * @param insn {@code non-null;} insn whos sources to process
    718      */
    719     private void adjustAndMapSourceRangeRange(NormalSsaInsn insn) {
    720         int newRegStart = findRangeAndAdjust(insn);
    721 
    722         RegisterSpecList sources = insn.getSources();
    723         int szSources = sources.size();
    724         int nextRopReg = newRegStart;
    725 
    726         for (int i = 0; i < szSources; i++) {
    727             RegisterSpec source = sources.get(i);
    728             int sourceReg = source.getReg();
    729             int category = source.getCategory();
    730             int curRopReg = nextRopReg;
    731             nextRopReg += category;
    732 
    733             if (ssaRegsMapped.get(sourceReg)) {
    734                 continue;
    735             }
    736 
    737             LocalItem localItem = getLocalItemForReg(sourceReg);
    738             addMapping(source, curRopReg);
    739 
    740             if (localItem != null) {
    741                 markReserved(curRopReg, category);
    742                 ArrayList<RegisterSpec> similarRegisters
    743                         = localVariables.get(localItem);
    744 
    745                 int szSimilar = similarRegisters.size();
    746 
    747                 /*
    748                  * Try to map all SSA registers also associated with
    749                  * this local.
    750                  */
    751                 for (int j = 0; j < szSimilar; j++) {
    752                     RegisterSpec similarSpec = similarRegisters.get(j);
    753                     int similarReg = similarSpec.getReg();
    754 
    755                     // Don't map anything that's also a source.
    756                     if (-1 != sources.indexOfRegister(similarReg)) {
    757                         continue;
    758                     }
    759 
    760                     // Registers left unmapped will get handled later.
    761                     tryMapReg(similarSpec, curRopReg, category);
    762                 }
    763             }
    764         }
    765     }
    766 
    767     /**
    768      * Find a contiguous rop register range that fits the specified
    769      * instruction's sources. First, try to center the range around
    770      * sources that have already been mapped to rop registers. If that fails,
    771      * just find a new contiguous range that doesn't interfere.
    772      *
    773      * @param insn {@code non-null;} the insn whose sources need to
    774      * fit. Must be last insn in basic block.
    775      * @return {@code >= 0;} rop register of start of range
    776      */
    777     private int findRangeAndAdjust(NormalSsaInsn insn) {
    778         RegisterSpecList sources = insn.getSources();
    779         int szSources = sources.size();
    780         // the category for each source index
    781         int categoriesForIndex[] = new int[szSources];
    782         int rangeLength = 0;
    783 
    784         // Compute rangeLength and categoriesForIndex
    785         for (int i = 0; i < szSources; i++) {
    786             int category = sources.get(i).getCategory();
    787             categoriesForIndex[i] = category;
    788             rangeLength += categoriesForIndex[i];
    789         }
    790 
    791         // the highest score of fits tried so far
    792         int maxScore = Integer.MIN_VALUE;
    793         // the high scoring range's start
    794         int resultRangeStart = -1;
    795         // by source index: set of sources needing moves in high scoring plan
    796         BitSet resultMovesRequired = null;
    797 
    798         /*
    799          * First, go through each source that's already been mapped. Try
    800          * to center the range around the rop register this source is mapped
    801          * to.
    802          */
    803         int rangeStartOffset = 0;
    804         for (int i = 0; i < szSources; i++) {
    805             int ssaCenterReg = sources.get(i).getReg();
    806 
    807             if (i != 0) {
    808                 rangeStartOffset -= categoriesForIndex[i - 1];
    809             }
    810             if (!ssaRegsMapped.get(ssaCenterReg)) {
    811                 continue;
    812             }
    813 
    814             int rangeStart = mapper.oldToNew(ssaCenterReg) + rangeStartOffset;
    815 
    816             if (rangeStart < 0 || spansParamRange(rangeStart, rangeLength)) {
    817                 continue;
    818             }
    819 
    820             BitSet curMovesRequired = new BitSet(szSources);
    821 
    822             int fitWidth
    823                     = fitPlanForRange(rangeStart, insn, categoriesForIndex,
    824                     curMovesRequired);
    825 
    826             if (fitWidth < 0) {
    827                 continue;
    828             }
    829 
    830             int score = fitWidth - curMovesRequired.cardinality();
    831 
    832             if (score > maxScore) {
    833                 maxScore = score;
    834                 resultRangeStart = rangeStart;
    835                 resultMovesRequired = curMovesRequired;
    836             }
    837 
    838             if (fitWidth == rangeLength) {
    839                 // We can't do any better than this, so stop here
    840                 break;
    841             }
    842         }
    843 
    844         /*
    845          * If we were unable to find a plan for a fit centered around
    846          * an already-mapped source, just try to find a range of
    847          * registers we can move the range into.
    848          */
    849 
    850         if (resultRangeStart == -1) {
    851             resultMovesRequired = new BitSet(szSources);
    852 
    853             resultRangeStart = findAnyFittingRange(insn, rangeLength,
    854                     categoriesForIndex, resultMovesRequired);
    855         }
    856 
    857         /*
    858          * Now, insert any moves required.
    859          */
    860 
    861         for (int i = resultMovesRequired.nextSetBit(0); i >= 0;
    862              i = resultMovesRequired.nextSetBit(i+1)) {
    863             insn.changeOneSource(i, insertMoveBefore(insn, sources.get(i)));
    864         }
    865 
    866         return resultRangeStart;
    867     }
    868 
    869     /**
    870      * Finds an unreserved range that will fit the sources of the
    871      * specified instruction. Does not bother trying to center the range
    872      * around an already-mapped source register;
    873      *
    874      * @param insn {@code non-null;} insn to build range for
    875      * @param rangeLength {@code >=0;} length required in register units
    876      * @param categoriesForIndex {@code non-null;} indexed by source index;
    877      * the category for each source
    878      * @param outMovesRequired {@code non-null;} an output parameter indexed by
    879      * source index that will contain the set of sources which need
    880      * moves inserted
    881      * @return the rop register that starts the fitting range
    882      */
    883     private int findAnyFittingRange(NormalSsaInsn insn, int rangeLength,
    884             int[] categoriesForIndex, BitSet outMovesRequired) {
    885         int rangeStart = paramRangeEnd;
    886         while (true) {
    887             rangeStart = findNextUnreservedRopReg(rangeStart, rangeLength);
    888             int fitWidth
    889                     = fitPlanForRange(rangeStart, insn,
    890                     categoriesForIndex, outMovesRequired);
    891 
    892             if (fitWidth >= 0) {
    893                 break;
    894             }
    895             rangeStart++;
    896             outMovesRequired.clear();
    897         }
    898         return rangeStart;
    899     }
    900 
    901     /**
    902      * Attempts to build a plan for fitting a range of sources into rop
    903      * registers.
    904      *
    905      * @param ropReg {@code >= 0;} rop reg that begins range
    906      * @param insn {@code non-null;} insn to plan range for
    907      * @param categoriesForIndex {@code non-null;} indexed by source index;
    908      * the category for each source
    909      * @param outMovesRequired {@code non-null;} an output parameter indexed by
    910      * source index that will contain the set of sources which need
    911      * moves inserted
    912      * @return the width of the fit that that does not involve added moves or
    913      * {@code -1} if "no fit possible"
    914      */
    915     private int fitPlanForRange(int ropReg, NormalSsaInsn insn,
    916             int[] categoriesForIndex, BitSet outMovesRequired) {
    917         RegisterSpecList sources = insn.getSources();
    918         int szSources = sources.size();
    919         int fitWidth = 0;
    920         IntSet liveOut = insn.getBlock().getLiveOutRegs();
    921         RegisterSpecList liveOutSpecs = ssaSetToSpecs(liveOut);
    922 
    923         // An SSA reg may only be mapped into a range once.
    924         BitSet seen = new BitSet(ssaMeth.getRegCount());
    925 
    926         for (int i = 0; i < szSources ; i++) {
    927             RegisterSpec ssaSpec = sources.get(i);
    928             int ssaReg = ssaSpec.getReg();
    929             int category = categoriesForIndex[i];
    930 
    931             if (i != 0) {
    932                 ropReg += categoriesForIndex[i-1];
    933             }
    934 
    935             if (ssaRegsMapped.get(ssaReg)
    936                     && mapper.oldToNew(ssaReg) == ropReg) {
    937                 // This is a register that is already mapped appropriately.
    938                 fitWidth += category;
    939             } else if (rangeContainsReserved(ropReg, category)) {
    940                 fitWidth = -1;
    941                 break;
    942             } else if (!ssaRegsMapped.get(ssaReg)
    943                     && canMapReg(ssaSpec, ropReg)
    944                     && !seen.get(ssaReg)) {
    945                 // This is a register that can be mapped appropriately.
    946                 fitWidth += category;
    947             } else if (!mapper.areAnyPinned(liveOutSpecs, ropReg, category)
    948                     && !mapper.areAnyPinned(sources, ropReg, category)) {
    949                 /*
    950                  * This is a source that can be moved. We can insert a
    951                  * move as long as:
    952                  *
    953                  *   * no SSA register pinned to the desired rop reg
    954                  *     is live out on the block
    955                  *
    956                  *   * no SSA register pinned to desired rop reg is
    957                  *     a source of this insn (since this may require
    958                  *     overlapping moves, which we can't presently handle)
    959                  */
    960 
    961                 outMovesRequired.set(i);
    962             } else {
    963                 fitWidth = -1;
    964                 break;
    965             }
    966 
    967             seen.set(ssaReg);
    968         }
    969         return fitWidth;
    970     }
    971 
    972     /**
    973      * Converts a bit set of SSA registers into a RegisterSpecList containing
    974      * the definition specs of all the registers.
    975      *
    976      * @param ssaSet {@code non-null;} set of SSA registers
    977      * @return list of RegisterSpecs as noted above
    978      */
    979     RegisterSpecList ssaSetToSpecs(IntSet ssaSet) {
    980         RegisterSpecList result = new RegisterSpecList(ssaSet.elements());
    981 
    982         IntIterator iter = ssaSet.iterator();
    983 
    984         int i = 0;
    985         while (iter.hasNext()) {
    986             result.set(i++, getDefinitionSpecForSsaReg(iter.next()));
    987         }
    988 
    989         return result;
    990     }
    991 
    992     /**
    993      * Gets a local item associated with an ssa register, if one exists.
    994      *
    995      * @param ssaReg {@code >= 0;} SSA register
    996      * @return {@code null-ok;} associated local item or null
    997      */
    998     private LocalItem getLocalItemForReg(int ssaReg) {
    999         for (Map.Entry<LocalItem, ArrayList<RegisterSpec>> entry :
   1000                  localVariables.entrySet()) {
   1001             for (RegisterSpec spec : entry.getValue()) {
   1002                 if (spec.getReg() == ssaReg) {
   1003                     return entry.getKey();
   1004                 }
   1005             }
   1006         }
   1007 
   1008         return null;
   1009     }
   1010 
   1011     /**
   1012      * Attempts to map the sources and result of a phi to a common register.
   1013      * Will try existing mappings first, from most to least common. If none
   1014      * of the registers have mappings yet, a new mapping is created.
   1015      */
   1016     private void processPhiInsn(PhiInsn insn) {
   1017         RegisterSpec result = insn.getResult();
   1018         int resultReg = result.getReg();
   1019         int category = result.getCategory();
   1020 
   1021         RegisterSpecList sources = insn.getSources();
   1022         int sourcesSize = sources.size();
   1023 
   1024         // List of phi sources / result that need mapping
   1025         ArrayList<RegisterSpec> ssaRegs = new ArrayList<RegisterSpec>();
   1026 
   1027         // Track how many times a particular mapping is found
   1028         Multiset mapSet = new Multiset(sourcesSize + 1);
   1029 
   1030         /*
   1031          * If the result of the phi has an existing mapping, get it.
   1032          * Otherwise, add it to the list of regs that need mapping.
   1033          */
   1034         if (ssaRegsMapped.get(resultReg)) {
   1035             mapSet.add(mapper.oldToNew(resultReg));
   1036         } else {
   1037             ssaRegs.add(result);
   1038         }
   1039 
   1040         for (int i = 0; i < sourcesSize; i++) {
   1041             RegisterSpec source = sources.get(i);
   1042             SsaInsn def = ssaMeth.getDefinitionForRegister(source.getReg());
   1043             RegisterSpec sourceDef = def.getResult();
   1044             int sourceReg = sourceDef.getReg();
   1045 
   1046             /*
   1047              * If a source of the phi has an existing mapping, get it.
   1048              * Otherwise, add it to the list of regs that need mapping.
   1049              */
   1050             if (ssaRegsMapped.get(sourceReg)) {
   1051                 mapSet.add(mapper.oldToNew(sourceReg));
   1052             } else {
   1053                 ssaRegs.add(sourceDef);
   1054             }
   1055         }
   1056 
   1057         // Try all existing mappings, with the most common ones first
   1058         for (int i = 0; i < mapSet.getSize(); i++) {
   1059             int maxReg = mapSet.getAndRemoveHighestCount();
   1060             tryMapRegs(ssaRegs, maxReg, category, false);
   1061         }
   1062 
   1063         // Map any remaining unmapped regs with whatever fits
   1064         int mapReg = findNextUnreservedRopReg(paramRangeEnd, category);
   1065         while (!tryMapRegs(ssaRegs, mapReg, category, false)) {
   1066             mapReg = findNextUnreservedRopReg(mapReg + 1, category);
   1067         }
   1068     }
   1069 
   1070     // A set that tracks how often elements are added to it.
   1071     private static class Multiset {
   1072         private final int[] reg;
   1073         private final int[] count;
   1074         private int size;
   1075 
   1076         /**
   1077          * Constructs an instance.
   1078          *
   1079          * @param maxSize the maximum distinct elements the set may have
   1080          */
   1081         public Multiset(int maxSize) {
   1082             reg = new int[maxSize];
   1083             count = new int[maxSize];
   1084             size = 0;
   1085         }
   1086 
   1087         /**
   1088          * Adds an element to the set.
   1089          *
   1090          * @param element element to add
   1091          */
   1092         public void add(int element) {
   1093             for (int i = 0; i < size; i++) {
   1094                 if (reg[i] == element) {
   1095                     count[i]++;
   1096                     return;
   1097                 }
   1098             }
   1099 
   1100             reg[size] = element;
   1101             count[size] = 1;
   1102             size++;
   1103         }
   1104 
   1105         /**
   1106          * Searches the set for the element that has been added the most.
   1107          * In the case of a tie, the element that was added first is returned.
   1108          * Then, it clears the count on that element. The size of the set
   1109          * remains unchanged.
   1110          *
   1111          * @return element with the highest count
   1112          */
   1113         public int getAndRemoveHighestCount() {
   1114             int maxIndex = -1;
   1115             int maxReg = -1;
   1116             int maxCount = 0;
   1117 
   1118             for (int i = 0; i < size; i++) {
   1119                 if (maxCount < count[i]) {
   1120                     maxIndex = i;
   1121                     maxReg = reg[i];
   1122                     maxCount = count[i];
   1123                 }
   1124             }
   1125 
   1126             count[maxIndex] = 0;
   1127             return maxReg;
   1128         }
   1129 
   1130         /**
   1131          * Gets the number of distinct elements in the set.
   1132          *
   1133          * @return size of the set
   1134          */
   1135         public int getSize() {
   1136             return size;
   1137         }
   1138     }
   1139 }
   1140