Home | History | Annotate | Download | only in code
      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.dex.code;
     18 
     19 import com.android.dx.rop.code.RegisterSpec;
     20 import com.android.dx.rop.code.RegisterSpecList;
     21 import com.android.dx.rop.code.SourcePosition;
     22 import com.android.dx.ssa.RegisterMapper;
     23 import com.android.dx.util.AnnotatedOutput;
     24 import com.android.dx.util.Hex;
     25 import com.android.dx.util.TwoColumnOutput;
     26 
     27 import java.util.BitSet;
     28 
     29 /**
     30  * Base class for Dalvik instructions.
     31  */
     32 public abstract class DalvInsn {
     33     /**
     34      * the actual output address of this instance, if known, or
     35      * {@code -1} if not
     36      */
     37     private int address;
     38 
     39     /** the opcode; one of the constants from {@link Dops} */
     40     private final Dop opcode;
     41 
     42     /** {@code non-null;} source position */
     43     private final SourcePosition position;
     44 
     45     /** {@code non-null;} list of register arguments */
     46     private final RegisterSpecList registers;
     47 
     48     /**
     49      * Makes a move instruction, appropriate and ideal for the given arguments.
     50      *
     51      * @param position {@code non-null;} source position information
     52      * @param dest {@code non-null;} destination register
     53      * @param src {@code non-null;} source register
     54      * @return {@code non-null;} an appropriately-constructed instance
     55      */
     56     public static SimpleInsn makeMove(SourcePosition position,
     57             RegisterSpec dest, RegisterSpec src) {
     58         boolean category1 = dest.getCategory() == 1;
     59         boolean reference = dest.getType().isReference();
     60         int destReg = dest.getReg();
     61         int srcReg = src.getReg();
     62         Dop opcode;
     63 
     64         if ((srcReg | destReg) < 16) {
     65             opcode = reference ? Dops.MOVE_OBJECT :
     66                 (category1 ? Dops.MOVE : Dops.MOVE_WIDE);
     67         } else if (destReg < 256) {
     68             opcode = reference ? Dops.MOVE_OBJECT_FROM16 :
     69                 (category1 ? Dops.MOVE_FROM16 : Dops.MOVE_WIDE_FROM16);
     70         } else {
     71             opcode = reference ? Dops.MOVE_OBJECT_16 :
     72                 (category1 ? Dops.MOVE_16 : Dops.MOVE_WIDE_16);
     73         }
     74 
     75         return new SimpleInsn(opcode, position,
     76                               RegisterSpecList.make(dest, src));
     77     }
     78 
     79     /**
     80      * Constructs an instance. The output address of this instance is initially
     81      * unknown ({@code -1}).
     82      *
     83      * <p><b>Note:</b> In the unlikely event that an instruction takes
     84      * absolutely no registers (e.g., a {@code nop} or a
     85      * no-argument no-result static method call), then the given
     86      * register list may be passed as {@link
     87      * RegisterSpecList#EMPTY}.</p>
     88      *
     89      * @param opcode the opcode; one of the constants from {@link Dops}
     90      * @param position {@code non-null;} source position
     91      * @param registers {@code non-null;} register list, including a
     92      * result register if appropriate (that is, registers may be either
     93      * ins and outs)
     94      */
     95     public DalvInsn(Dop opcode, SourcePosition position,
     96                     RegisterSpecList registers) {
     97         if (opcode == null) {
     98             throw new NullPointerException("opcode == null");
     99         }
    100 
    101         if (position == null) {
    102             throw new NullPointerException("position == null");
    103         }
    104 
    105         if (registers == null) {
    106             throw new NullPointerException("registers == null");
    107         }
    108 
    109         this.address = -1;
    110         this.opcode = opcode;
    111         this.position = position;
    112         this.registers = registers;
    113     }
    114 
    115     /** {@inheritDoc} */
    116     @Override
    117     public final String toString() {
    118         StringBuffer sb = new StringBuffer(100);
    119 
    120         sb.append(identifierString());
    121         sb.append(' ');
    122         sb.append(position);
    123 
    124         sb.append(": ");
    125         sb.append(opcode.getName());
    126 
    127         boolean needComma = false;
    128         if (registers.size() != 0) {
    129             sb.append(registers.toHuman(" ", ", ", null));
    130             needComma = true;
    131         }
    132 
    133         String extra = argString();
    134         if (extra != null) {
    135             if (needComma) {
    136                 sb.append(',');
    137             }
    138             sb.append(' ');
    139             sb.append(extra);
    140         }
    141 
    142         return sb.toString();
    143     }
    144 
    145     /**
    146      * Gets whether the address of this instruction is known.
    147      *
    148      * @see #getAddress
    149      * @see #setAddress
    150      */
    151     public final boolean hasAddress() {
    152         return (address >= 0);
    153     }
    154 
    155     /**
    156      * Gets the output address of this instruction, if it is known. This throws
    157      * a {@code RuntimeException} if it has not yet been set.
    158      *
    159      * @see #setAddress
    160      *
    161      * @return {@code >= 0;} the output address
    162      */
    163     public final int getAddress() {
    164         if (address < 0) {
    165             throw new RuntimeException("address not yet known");
    166         }
    167 
    168         return address;
    169     }
    170 
    171     /**
    172      * Gets the opcode.
    173      *
    174      * @return {@code non-null;} the opcode
    175      */
    176     public final Dop getOpcode() {
    177         return opcode;
    178     }
    179 
    180     /**
    181      * Gets the source position.
    182      *
    183      * @return {@code non-null;} the source position
    184      */
    185     public final SourcePosition getPosition() {
    186         return position;
    187     }
    188 
    189     /**
    190      * Gets the register list for this instruction.
    191      *
    192      * @return {@code non-null;} the registers
    193      */
    194     public final RegisterSpecList getRegisters() {
    195         return registers;
    196     }
    197 
    198     /**
    199      * Returns whether this instance's opcode uses a result register.
    200      * This method is a convenient shorthand for
    201      * {@code getOpcode().hasResult()}.
    202      *
    203      * @return {@code true} iff this opcode uses a result register
    204      */
    205     public final boolean hasResult() {
    206         return opcode.hasResult();
    207     }
    208 
    209     /**
    210      * Gets the minimum distinct registers required for this instruction.
    211      * Uses the given BitSet to determine which registers require
    212      * replacement, and ignores registers that are already compatible.
    213      * This assumes that the result (if any) can share registers with the
    214      * sources (if any), that each source register is unique, and that
    215      * (to be explicit here) category-2 values take up two consecutive
    216      * registers.
    217      *
    218      * @param compatRegs {@code non-null;} set of compatible registers
    219      * @return {@code >= 0;} the minimum distinct register requirement
    220      */
    221     public final int getMinimumRegisterRequirement(BitSet compatRegs) {
    222         boolean hasResult = hasResult();
    223         int regSz = registers.size();
    224         int resultRequirement = 0;
    225         int sourceRequirement = 0;
    226 
    227         if (hasResult && !compatRegs.get(0)) {
    228             resultRequirement = registers.get(0).getCategory();
    229         }
    230 
    231         for (int i = hasResult ? 1 : 0; i < regSz; i++) {
    232             if (!compatRegs.get(i)) {
    233                 sourceRequirement += registers.get(i).getCategory();
    234             }
    235         }
    236 
    237         return Math.max(sourceRequirement, resultRequirement);
    238     }
    239 
    240     /**
    241      * Gets the instruction that is equivalent to this one, except that
    242      * it uses sequential registers starting at {@code 0} (storing
    243      * the result, if any, in register {@code 0} as well).
    244      *
    245      * @return {@code non-null;} the replacement
    246      */
    247     public DalvInsn getLowRegVersion() {
    248         RegisterSpecList regs =
    249             registers.withExpandedRegisters(0, hasResult(), null);
    250         return withRegisters(regs);
    251     }
    252 
    253     /**
    254      * Gets the instruction prefix required, if any, to use in an expanded
    255      * version of this instance. Will not generate moves for registers
    256      * marked compatible to the format by the given BitSet.
    257      *
    258      * @see #expandedVersion
    259      *
    260      * @param compatRegs {@code non-null;} set of compatible registers
    261      * @return {@code null-ok;} the prefix, if any
    262      */
    263     public DalvInsn expandedPrefix(BitSet compatRegs) {
    264         RegisterSpecList regs = registers;
    265         boolean firstBit = compatRegs.get(0);
    266 
    267         if (hasResult()) compatRegs.set(0);
    268 
    269         regs = regs.subset(compatRegs);
    270 
    271         if (hasResult()) compatRegs.set(0, firstBit);
    272 
    273         if (regs.size() == 0) return null;
    274 
    275         return new HighRegisterPrefix(position, regs);
    276     }
    277 
    278     /**
    279      * Gets the instruction suffix required, if any, to use in an expanded
    280      * version of this instance. Will not generate a move for a register
    281      * marked compatible to the format by the given BitSet.
    282      *
    283      * @see #expandedVersion
    284      *
    285      * @param compatRegs {@code non-null;} set of compatible registers
    286      * @return {@code null-ok;} the suffix, if any
    287      */
    288     public DalvInsn expandedSuffix(BitSet compatRegs) {
    289         if (hasResult() && !compatRegs.get(0)) {
    290             RegisterSpec r = registers.get(0);
    291             return makeMove(position, r, r.withReg(0));
    292         } else {
    293             return null;
    294         }
    295     }
    296 
    297     /**
    298      * Gets the instruction that is equivalent to this one, except that
    299      * it replaces incompatible registers with sequential registers
    300      * starting at {@code 0} (storing the result, if any, in register
    301      * {@code 0} as well). The sequence of instructions from
    302      * {@link #expandedPrefix} and {@link #expandedSuffix} (if non-null)
    303      * surrounding the result of a call to this method are the expanded
    304      * transformation of this instance, and it is guaranteed that the
    305      * number of low registers used will be the number returned by
    306      * {@link #getMinimumRegisterRequirement}.
    307      *
    308      * @param compatRegs {@code non-null;} set of compatible registers
    309      * @return {@code non-null;} the replacement
    310      */
    311     public DalvInsn expandedVersion(BitSet compatRegs) {
    312         RegisterSpecList regs =
    313             registers.withExpandedRegisters(0, hasResult(), compatRegs);
    314         return withRegisters(regs);
    315     }
    316 
    317     /**
    318      * Gets the short identifier for this instruction. This is its
    319      * address, if assigned, or its identity hashcode if not.
    320      *
    321      * @return {@code non-null;} the identifier
    322      */
    323     public final String identifierString() {
    324         if (address != -1) {
    325             return String.format("%04x", address);
    326         }
    327 
    328         return Hex.u4(System.identityHashCode(this));
    329     }
    330 
    331     /**
    332      * Returns the string form of this instance suitable for inclusion in
    333      * a human-oriented listing dump. This method will return {@code null}
    334      * if this instance should not appear in a listing.
    335      *
    336      * @param prefix {@code non-null;} prefix before the address; each follow-on
    337      * line will be indented to match as well
    338      * @param width {@code >= 0;} the width of the output or {@code 0} for
    339      * unlimited width
    340      * @param noteIndices whether to include an explicit notation of
    341      * constant pool indices
    342      * @return {@code null-ok;} the string form or {@code null} if this
    343      * instance should not appear in a listing
    344      */
    345     public final String listingString(String prefix, int width,
    346             boolean noteIndices) {
    347         String insnPerSe = listingString0(noteIndices);
    348 
    349         if (insnPerSe == null) {
    350             return null;
    351         }
    352 
    353         String addr = prefix + identifierString() + ": ";
    354         int w1 = addr.length();
    355         int w2 = (width == 0) ? insnPerSe.length() : (width - w1);
    356 
    357         return TwoColumnOutput.toString(addr, w1, "", insnPerSe, w2);
    358     }
    359 
    360     /**
    361      * Sets the output address.
    362      *
    363      * @param address {@code >= 0;} the output address
    364      */
    365     public final void setAddress(int address) {
    366         if (address < 0) {
    367             throw new IllegalArgumentException("address < 0");
    368         }
    369 
    370         this.address = address;
    371     }
    372 
    373     /**
    374      * Gets the address immediately after this instance. This is only
    375      * calculable if this instance's address is known, and it is equal
    376      * to the address plus the length of the instruction format of this
    377      * instance's opcode.
    378      *
    379      * @return {@code >= 0;} the next address
    380      */
    381     public final int getNextAddress() {
    382         return getAddress() + codeSize();
    383     }
    384 
    385     /**
    386      * Returns an instance that is just like this one, except that the
    387      * register list is mapped by using {@code mapper}.
    388      *
    389      * @param mapper {@code non-null;} used to map registers
    390      * @return {@code non-null;} an appropriately-constructed instance
    391      */
    392     public DalvInsn withMapper(RegisterMapper mapper) {
    393       return withRegisters(mapper.map(getRegisters()));
    394     }
    395 
    396     /**
    397      * Gets the size of this instruction, in 16-bit code units.
    398      *
    399      * @return {@code >= 0;} the code size of this instruction
    400      */
    401     public abstract int codeSize();
    402 
    403     /**
    404      * Writes this instance to the given output. This method should
    405      * never annotate the output.
    406      *
    407      * @param out {@code non-null;} where to write to
    408      */
    409     public abstract void writeTo(AnnotatedOutput out);
    410 
    411     /**
    412      * Returns an instance that is just like this one, except that its
    413      * opcode is replaced by the one given, and its address is reset.
    414      *
    415      * @param opcode {@code non-null;} the new opcode
    416      * @return {@code non-null;} an appropriately-constructed instance
    417      */
    418     public abstract DalvInsn withOpcode(Dop opcode);
    419 
    420     /**
    421      * Returns an instance that is just like this one, except that all
    422      * register references have been offset by the given delta, and its
    423      * address is reset.
    424      *
    425      * @param delta the amount to offset register references by
    426      * @return {@code non-null;} an appropriately-constructed instance
    427      */
    428     public abstract DalvInsn withRegisterOffset(int delta);
    429 
    430     /**
    431      * Returns an instance that is just like this one, except that the
    432      * register list is replaced by the given one, and its address is
    433      * reset.
    434      *
    435      * @param registers {@code non-null;} new register list
    436      * @return {@code non-null;} an appropriately-constructed instance
    437      */
    438     public abstract DalvInsn withRegisters(RegisterSpecList registers);
    439 
    440     /**
    441      * Gets the string form for any arguments to this instance. Subclasses
    442      * must override this.
    443      *
    444      * @return {@code null-ok;} the string version of any arguments or
    445      * {@code null} if there are none
    446      */
    447     protected abstract String argString();
    448 
    449     /**
    450      * Helper for {@link #listingString}, which returns the string
    451      * form of this instance suitable for inclusion in a
    452      * human-oriented listing dump, not including the instruction
    453      * address and without respect for any output formatting. This
    454      * method should return {@code null} if this instance should
    455      * not appear in a listing.
    456      *
    457      * @param noteIndices whether to include an explicit notation of
    458      * constant pool indices
    459      * @return {@code null-ok;} the listing string
    460      */
    461     protected abstract String listingString0(boolean noteIndices);
    462 }
    463