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.cst.Constant;
     20 import com.android.dx.rop.type.Type;
     21 import java.util.HashSet;
     22 
     23 /**
     24  * Container for all the pieces of a concrete method. Each instance
     25  * corresponds to a {@code code} structure in a {@code .dex} file.
     26  */
     27 public final class DalvCode {
     28     /**
     29      * how much position info to preserve; one of the static
     30      * constants in {@link PositionList}
     31      */
     32     private final int positionInfo;
     33 
     34     /**
     35      * {@code null-ok;} the instruction list, ready for final processing;
     36      * nulled out in {@link #finishProcessingIfNecessary}
     37      */
     38     private OutputFinisher unprocessedInsns;
     39 
     40     /**
     41      * {@code non-null;} unprocessed catch table;
     42      * nulled out in {@link #finishProcessingIfNecessary}
     43      */
     44     private CatchBuilder unprocessedCatches;
     45 
     46     /**
     47      * {@code null-ok;} catch table; set in
     48      * {@link #finishProcessingIfNecessary}
     49      */
     50     private CatchTable catches;
     51 
     52     /**
     53      * {@code null-ok;} source positions list; set in
     54      * {@link #finishProcessingIfNecessary}
     55      */
     56     private PositionList positions;
     57 
     58     /**
     59      * {@code null-ok;} local variable list; set in
     60      * {@link #finishProcessingIfNecessary}
     61      */
     62     private LocalList locals;
     63 
     64     /**
     65      * {@code null-ok;} the processed instruction list; set in
     66      * {@link #finishProcessingIfNecessary}
     67      */
     68     private DalvInsnList insns;
     69 
     70     /**
     71      * Constructs an instance.
     72      *
     73      * @param positionInfo how much position info to preserve; one of the
     74      * static constants in {@link PositionList}
     75      * @param unprocessedInsns {@code non-null;} the instruction list, ready
     76      * for final processing
     77      * @param unprocessedCatches {@code non-null;} unprocessed catch
     78      * (exception handler) table
     79      */
     80     public DalvCode(int positionInfo, OutputFinisher unprocessedInsns,
     81             CatchBuilder unprocessedCatches) {
     82         if (unprocessedInsns == null) {
     83             throw new NullPointerException("unprocessedInsns == null");
     84         }
     85 
     86         if (unprocessedCatches == null) {
     87             throw new NullPointerException("unprocessedCatches == null");
     88         }
     89 
     90         this.positionInfo = positionInfo;
     91         this.unprocessedInsns = unprocessedInsns;
     92         this.unprocessedCatches = unprocessedCatches;
     93         this.catches = null;
     94         this.positions = null;
     95         this.locals = null;
     96         this.insns = null;
     97     }
     98 
     99     /**
    100      * Finish up processing of the method.
    101      */
    102     private void finishProcessingIfNecessary() {
    103         if (insns != null) {
    104             return;
    105         }
    106 
    107         insns = unprocessedInsns.finishProcessingAndGetList();
    108         positions = PositionList.make(insns, positionInfo);
    109         locals = LocalList.make(insns);
    110         catches = unprocessedCatches.build();
    111 
    112         // Let them be gc'ed.
    113         unprocessedInsns = null;
    114         unprocessedCatches = null;
    115     }
    116 
    117     /**
    118      * Assign indices in all instructions that need them, using the
    119      * given callback to perform lookups. This must be called before
    120      * {@link #getInsns}.
    121      *
    122      * @param callback {@code non-null;} callback object
    123      */
    124     public void assignIndices(AssignIndicesCallback callback) {
    125         unprocessedInsns.assignIndices(callback);
    126     }
    127 
    128     /**
    129      * Gets whether this instance has any position data to represent.
    130      *
    131      * @return {@code true} iff this instance has any position
    132      * data to represent
    133      */
    134     public boolean hasPositions() {
    135         return (positionInfo != PositionList.NONE)
    136             && unprocessedInsns.hasAnyPositionInfo();
    137     }
    138 
    139     /**
    140      * Gets whether this instance has any local variable data to represent.
    141      *
    142      * @return {@code true} iff this instance has any local variable
    143      * data to represent
    144      */
    145     public boolean hasLocals() {
    146         return unprocessedInsns.hasAnyLocalInfo();
    147     }
    148 
    149     /**
    150      * Gets whether this instance has any catches at all (either typed
    151      * or catch-all).
    152      *
    153      * @return whether this instance has any catches at all
    154      */
    155     public boolean hasAnyCatches() {
    156         return unprocessedCatches.hasAnyCatches();
    157     }
    158 
    159     /**
    160      * Gets the set of catch types handled anywhere in the code.
    161      *
    162      * @return {@code non-null;} the set of catch types
    163      */
    164     public HashSet<Type> getCatchTypes() {
    165         return unprocessedCatches.getCatchTypes();
    166     }
    167 
    168     /**
    169      * Gets the set of all constants referred to by instructions in
    170      * the code.
    171      *
    172      * @return {@code non-null;} the set of constants
    173      */
    174     public HashSet<Constant> getInsnConstants() {
    175         return unprocessedInsns.getAllConstants();
    176     }
    177 
    178     /**
    179      * Gets the list of instructions.
    180      *
    181      * @return {@code non-null;} the instruction list
    182      */
    183     public DalvInsnList getInsns() {
    184         finishProcessingIfNecessary();
    185         return insns;
    186     }
    187 
    188     /**
    189      * Gets the catch (exception handler) table.
    190      *
    191      * @return {@code non-null;} the catch table
    192      */
    193     public CatchTable getCatches() {
    194         finishProcessingIfNecessary();
    195         return catches;
    196     }
    197 
    198     /**
    199      * Gets the source positions list.
    200      *
    201      * @return {@code non-null;} the source positions list
    202      */
    203     public PositionList getPositions() {
    204         finishProcessingIfNecessary();
    205         return positions;
    206     }
    207 
    208     /**
    209      * Gets the source positions list.
    210      *
    211      * @return {@code non-null;} the source positions list
    212      */
    213     public LocalList getLocals() {
    214         finishProcessingIfNecessary();
    215         return locals;
    216     }
    217 
    218     /**
    219      * Class used as a callback for {@link #assignIndices}.
    220      */
    221     public static interface AssignIndicesCallback {
    222         /**
    223          * Gets the index for the given constant.
    224          *
    225          * @param cst {@code non-null;} the constant
    226          * @return {@code >= -1;} the index or {@code -1} if the constant
    227          * shouldn't actually be reified with an index
    228          */
    229         public int getIndex(Constant cst);
    230     }
    231 }
    232