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.RegisterSpecList;
     20 import com.android.dx.rop.code.SourcePosition;
     21 import com.android.dx.rop.cst.Constant;
     22 
     23 /**
     24  * Instruction which has a single constant argument in addition
     25  * to all the normal instruction information.
     26  */
     27 public final class CstInsn extends FixedSizeInsn {
     28     /** {@code non-null;} the constant argument for this instruction */
     29     private final Constant constant;
     30 
     31     /**
     32      * {@code >= -1;} the constant pool index for {@link #constant}, or
     33      * {@code -1} if not yet set
     34      */
     35     private int index;
     36 
     37     /**
     38      * {@code >= -1;} the constant pool index for the class reference in
     39      * {@link #constant} if any, or {@code -1} if not yet set
     40      */
     41     private int classIndex;
     42 
     43     /**
     44      * Constructs an instance. The output address of this instance is
     45      * initially unknown ({@code -1}) as is the constant pool index.
     46      *
     47      * @param opcode the opcode; one of the constants from {@link Dops}
     48      * @param position {@code non-null;} source position
     49      * @param registers {@code non-null;} register list, including a
     50      * result register if appropriate (that is, registers may be either
     51      * ins or outs)
     52      * @param constant {@code non-null;} constant argument
     53      */
     54     public CstInsn(Dop opcode, SourcePosition position,
     55                    RegisterSpecList registers, Constant constant) {
     56         super(opcode, position, registers);
     57 
     58         if (constant == null) {
     59             throw new NullPointerException("constant == null");
     60         }
     61 
     62         this.constant = constant;
     63         this.index = -1;
     64         this.classIndex = -1;
     65     }
     66 
     67     /** {@inheritDoc} */
     68     @Override
     69     public DalvInsn withOpcode(Dop opcode) {
     70         CstInsn result =
     71             new CstInsn(opcode, getPosition(), getRegisters(), constant);
     72 
     73         if (index >= 0) {
     74             result.setIndex(index);
     75         }
     76 
     77         if (classIndex >= 0) {
     78             result.setClassIndex(classIndex);
     79         }
     80 
     81         return result;
     82     }
     83 
     84     /** {@inheritDoc} */
     85     @Override
     86     public DalvInsn withRegisters(RegisterSpecList registers) {
     87         CstInsn result =
     88             new CstInsn(getOpcode(), getPosition(), registers, constant);
     89 
     90         if (index >= 0) {
     91             result.setIndex(index);
     92         }
     93 
     94         if (classIndex >= 0) {
     95             result.setClassIndex(classIndex);
     96         }
     97 
     98         return result;
     99     }
    100 
    101     /**
    102      * Gets the constant argument.
    103      *
    104      * @return {@code non-null;} the constant argument
    105      */
    106     public Constant getConstant() {
    107         return constant;
    108     }
    109 
    110     /**
    111      * Gets the constant's index. It is only valid to call this after
    112      * {@link #setIndex} has been called.
    113      *
    114      * @return {@code >= 0;} the constant pool index
    115      */
    116     public int getIndex() {
    117         if (index < 0) {
    118             throw new RuntimeException("index not yet set for " + constant);
    119         }
    120 
    121         return index;
    122     }
    123 
    124     /**
    125      * Returns whether the constant's index has been set for this instance.
    126      *
    127      * @see #setIndex
    128      *
    129      * @return {@code true} iff the index has been set
    130      */
    131     public boolean hasIndex() {
    132         return (index >= 0);
    133     }
    134 
    135     /**
    136      * Sets the constant's index. It is only valid to call this method once
    137      * per instance.
    138      *
    139      * @param index {@code >= 0;} the constant pool index
    140      */
    141     public void setIndex(int index) {
    142         if (index < 0) {
    143             throw new IllegalArgumentException("index < 0");
    144         }
    145 
    146         if (this.index >= 0) {
    147             throw new RuntimeException("index already set");
    148         }
    149 
    150         this.index = index;
    151     }
    152 
    153     /**
    154      * Gets the constant's class index. It is only valid to call this after
    155      * {@link #setClassIndex} has been called.
    156      *
    157      * @return {@code >= 0;} the constant's class's constant pool index
    158      */
    159     public int getClassIndex() {
    160         if (classIndex < 0) {
    161             throw new RuntimeException("class index not yet set");
    162         }
    163 
    164         return classIndex;
    165     }
    166 
    167     /**
    168      * Returns whether the constant's class index has been set for this
    169      * instance.
    170      *
    171      * @see #setClassIndex
    172      *
    173      * @return {@code true} iff the index has been set
    174      */
    175     public boolean hasClassIndex() {
    176         return (classIndex >= 0);
    177     }
    178 
    179     /**
    180      * Sets the constant's class index. This is the constant pool index
    181      * for the class referred to by this instance's constant. Only
    182      * reference constants have a class, so it is only on instances
    183      * with reference constants that this method should ever be
    184      * called. It is only valid to call this method once per instance.
    185      *
    186      * @param index {@code >= 0;} the constant's class's constant pool index
    187      */
    188     public void setClassIndex(int index) {
    189         if (index < 0) {
    190             throw new IllegalArgumentException("index < 0");
    191         }
    192 
    193         if (this.classIndex >= 0) {
    194             throw new RuntimeException("class index already set");
    195         }
    196 
    197         this.classIndex = index;
    198     }
    199 
    200     /** {@inheritDoc} */
    201     @Override
    202     protected String argString() {
    203         return constant.toHuman();
    204     }
    205 }
    206