/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.dx.dex.code; import com.android.dx.rop.code.RegisterSpecList; import com.android.dx.rop.code.SourcePosition; import com.android.dx.rop.cst.Constant; /** * Instruction which has a single constant argument in addition * to all the normal instruction information. */ public final class CstInsn extends FixedSizeInsn { /** {@code non-null;} the constant argument for this instruction */ private final Constant constant; /** * {@code >= -1;} the constant pool index for {@link #constant}, or * {@code -1} if not yet set */ private int index; /** * {@code >= -1;} the constant pool index for the class reference in * {@link #constant} if any, or {@code -1} if not yet set */ private int classIndex; /** * Constructs an instance. The output address of this instance is * initially unknown ({@code -1}) as is the constant pool index. * * @param opcode the opcode; one of the constants from {@link Dops} * @param position {@code non-null;} source position * @param registers {@code non-null;} register list, including a * result register if appropriate (that is, registers may be either * ins or outs) * @param constant {@code non-null;} constant argument */ public CstInsn(Dop opcode, SourcePosition position, RegisterSpecList registers, Constant constant) { super(opcode, position, registers); if (constant == null) { throw new NullPointerException("constant == null"); } this.constant = constant; this.index = -1; this.classIndex = -1; } /** {@inheritDoc} */ @Override public DalvInsn withOpcode(Dop opcode) { CstInsn result = new CstInsn(opcode, getPosition(), getRegisters(), constant); if (index >= 0) { result.setIndex(index); } if (classIndex >= 0) { result.setClassIndex(classIndex); } return result; } /** {@inheritDoc} */ @Override public DalvInsn withRegisters(RegisterSpecList registers) { CstInsn result = new CstInsn(getOpcode(), getPosition(), registers, constant); if (index >= 0) { result.setIndex(index); } if (classIndex >= 0) { result.setClassIndex(classIndex); } return result; } /** * Gets the constant argument. * * @return {@code non-null;} the constant argument */ public Constant getConstant() { return constant; } /** * Gets the constant's index. It is only valid to call this after * {@link #setIndex} has been called. * * @return {@code >= 0;} the constant pool index */ public int getIndex() { if (index < 0) { throw new RuntimeException("index not yet set for " + constant); } return index; } /** * Returns whether the constant's index has been set for this instance. * * @see #setIndex * * @return {@code true} iff the index has been set */ public boolean hasIndex() { return (index >= 0); } /** * Sets the constant's index. It is only valid to call this method once * per instance. * * @param index {@code >= 0;} the constant pool index */ public void setIndex(int index) { if (index < 0) { throw new IllegalArgumentException("index < 0"); } if (this.index >= 0) { throw new RuntimeException("index already set"); } this.index = index; } /** * Gets the constant's class index. It is only valid to call this after * {@link #setClassIndex} has been called. * * @return {@code >= 0;} the constant's class's constant pool index */ public int getClassIndex() { if (classIndex < 0) { throw new RuntimeException("class index not yet set"); } return classIndex; } /** * Returns whether the constant's class index has been set for this * instance. * * @see #setClassIndex * * @return {@code true} iff the index has been set */ public boolean hasClassIndex() { return (classIndex >= 0); } /** * Sets the constant's class index. This is the constant pool index * for the class referred to by this instance's constant. Only * reference constants have a class, so it is only on instances * with reference constants that this method should ever be * called. It is only valid to call this method once per instance. * * @param index {@code >= 0;} the constant's class's constant pool index */ public void setClassIndex(int index) { if (index < 0) { throw new IllegalArgumentException("index < 0"); } if (this.classIndex >= 0) { throw new RuntimeException("class index already set"); } this.classIndex = index; } /** {@inheritDoc} */ @Override protected String argString() { return constant.toHuman(); } }