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.io.Opcodes;
     20 import com.android.dx.rop.cst.Constant;
     21 import com.android.dx.rop.cst.CstBaseMethodRef;
     22 import com.android.dx.util.AnnotatedOutput;
     23 import com.android.dx.util.ExceptionWithContext;
     24 import com.android.dx.util.FixedSizeList;
     25 import com.android.dx.util.IndentingWriter;
     26 
     27 import java.io.IOException;
     28 import java.io.OutputStream;
     29 import java.io.OutputStreamWriter;
     30 import java.io.Writer;
     31 import java.util.ArrayList;
     32 
     33 /**
     34  * List of {@link DalvInsn} instances.
     35  */
     36 public final class DalvInsnList extends FixedSizeList {
     37 
     38     /**
     39      * The amount of register space, in register units, required for this
     40      * code block. This may be greater than the largest observed register+
     41      * category because the method this code block exists in may
     42      * specify arguments that are unused by the method.
     43      */
     44     private final int regCount;
     45 
     46     /**
     47      * Constructs and returns an immutable instance whose elements are
     48      * identical to the ones in the given list, in the same order.
     49      *
     50      * @param list {@code non-null;} the list to use for elements
     51      * @param regCount count, in register-units, of the number of registers
     52      * this code block requires.
     53      * @return {@code non-null;} an appropriately-constructed instance of this
     54      * class
     55      */
     56     public static DalvInsnList makeImmutable(ArrayList<DalvInsn> list,
     57             int regCount) {
     58         int size = list.size();
     59         DalvInsnList result = new DalvInsnList(size, regCount);
     60 
     61         for (int i = 0; i < size; i++) {
     62             result.set(i, list.get(i));
     63         }
     64 
     65         result.setImmutable();
     66         return result;
     67     }
     68 
     69     /**
     70      * Constructs an instance. All indices initially contain {@code null}.
     71      *
     72      * @param size the size of the list
     73      */
     74     public DalvInsnList(int size, int regCount) {
     75         super(size);
     76         this.regCount = regCount;
     77     }
     78 
     79     /**
     80      * Gets the element at the given index. It is an error to call
     81      * this with the index for an element which was never set; if you
     82      * do that, this will throw {@code NullPointerException}.
     83      *
     84      * @param n {@code >= 0, < size();} which index
     85      * @return {@code non-null;} element at that index
     86      */
     87     public DalvInsn get(int n) {
     88         return (DalvInsn) get0(n);
     89     }
     90 
     91     /**
     92      * Sets the instruction at the given index.
     93      *
     94      * @param n {@code >= 0, < size();} which index
     95      * @param insn {@code non-null;} the instruction to set at {@code n}
     96      */
     97     public void set(int n, DalvInsn insn) {
     98         set0(n, insn);
     99     }
    100 
    101     /**
    102      * Gets the size of this instance, in 16-bit code units. This will only
    103      * return a meaningful result if the instructions in this instance all
    104      * have valid addresses.
    105      *
    106      * @return {@code >= 0;} the size
    107      */
    108     public int codeSize() {
    109         int sz = size();
    110 
    111         if (sz == 0) {
    112             return 0;
    113         }
    114 
    115         DalvInsn last = get(sz - 1);
    116         return last.getNextAddress();
    117     }
    118 
    119     /**
    120      * Writes all the instructions in this instance to the given output
    121      * destination.
    122      *
    123      * @param out {@code non-null;} where to write to
    124      */
    125     public void writeTo(AnnotatedOutput out) {
    126         int startCursor = out.getCursor();
    127         int sz = size();
    128 
    129         if (out.annotates()) {
    130             boolean verbose = out.isVerbose();
    131 
    132             for (int i = 0; i < sz; i++) {
    133                 DalvInsn insn = (DalvInsn) get0(i);
    134                 int codeBytes = insn.codeSize() * 2;
    135                 String s;
    136 
    137                 if ((codeBytes != 0) || verbose) {
    138                     s = insn.listingString("  ", out.getAnnotationWidth(),
    139                             true);
    140                 } else {
    141                     s = null;
    142                 }
    143 
    144                 if (s != null) {
    145                     out.annotate(codeBytes, s);
    146                 } else if (codeBytes != 0) {
    147                     out.annotate(codeBytes, "");
    148                 }
    149             }
    150         }
    151 
    152         for (int i = 0; i < sz; i++) {
    153             DalvInsn insn = (DalvInsn) get0(i);
    154             try {
    155                 insn.writeTo(out);
    156             } catch (RuntimeException ex) {
    157                 throw ExceptionWithContext.withContext(ex,
    158                         "...while writing " + insn);
    159             }
    160         }
    161 
    162         // Sanity check of the amount written.
    163         int written = (out.getCursor() - startCursor) / 2;
    164         if (written != codeSize()) {
    165             throw new RuntimeException("write length mismatch; expected " +
    166                     codeSize() + " but actually wrote " + written);
    167         }
    168     }
    169 
    170     /**
    171      * Gets the minimum required register count implied by this
    172      * instance.  This includes any unused parameters that could
    173      * potentially be at the top of the register space.
    174      * @return {@code >= 0;} the required registers size
    175      */
    176     public int getRegistersSize() {
    177         return regCount;
    178     }
    179 
    180     /**
    181      * Gets the size of the outgoing arguments area required by this
    182      * method. This is equal to the largest argument word count of any
    183      * method referred to by this instance.
    184      *
    185      * @return {@code >= 0;} the required outgoing arguments size
    186      */
    187     public int getOutsSize() {
    188         int sz = size();
    189         int result = 0;
    190 
    191         for (int i = 0; i < sz; i++) {
    192             DalvInsn insn = (DalvInsn) get0(i);
    193 
    194             if (!(insn instanceof CstInsn)) {
    195                 continue;
    196             }
    197 
    198             Constant cst = ((CstInsn) insn).getConstant();
    199 
    200             if (!(cst instanceof CstBaseMethodRef)) {
    201                 continue;
    202             }
    203 
    204             boolean isStatic =
    205                 (insn.getOpcode().getFamily() == Opcodes.INVOKE_STATIC);
    206             int count =
    207                 ((CstBaseMethodRef) cst).getParameterWordCount(isStatic);
    208 
    209             if (count > result) {
    210                 result = count;
    211             }
    212         }
    213 
    214         return result;
    215     }
    216 
    217     /**
    218      * Does a human-friendly dump of this instance.
    219      *
    220      * @param out {@code non-null;} where to dump
    221      * @param prefix {@code non-null;} prefix to attach to each line of output
    222      * @param verbose whether to be verbose; verbose output includes
    223      * lines for zero-size instructions and explicit constant pool indices
    224      */
    225     public void debugPrint(Writer out, String prefix, boolean verbose) {
    226         IndentingWriter iw = new IndentingWriter(out, 0, prefix);
    227         int sz = size();
    228 
    229         try {
    230             for (int i = 0; i < sz; i++) {
    231                 DalvInsn insn = (DalvInsn) get0(i);
    232                 String s;
    233 
    234                 if ((insn.codeSize() != 0) || verbose) {
    235                     s = insn.listingString("", 0, verbose);
    236                 } else {
    237                     s = null;
    238                 }
    239 
    240                 if (s != null) {
    241                     iw.write(s);
    242                 }
    243             }
    244 
    245             iw.flush();
    246         } catch (IOException ex) {
    247             throw new RuntimeException(ex);
    248         }
    249     }
    250 
    251     /**
    252      * Does a human-friendly dump of this instance.
    253      *
    254      * @param out {@code non-null;} where to dump
    255      * @param prefix {@code non-null;} prefix to attach to each line of output
    256      * @param verbose whether to be verbose; verbose output includes
    257      * lines for zero-size instructions
    258      */
    259     public void debugPrint(OutputStream out, String prefix, boolean verbose) {
    260         Writer w = new OutputStreamWriter(out);
    261         debugPrint(w, prefix, verbose);
    262 
    263         try {
    264             w.flush();
    265         } catch (IOException ex) {
    266             throw new RuntimeException(ex);
    267         }
    268     }
    269 }
    270