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