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.OpcodeInfo; 20 import com.android.dx.io.Opcodes; 21 22 /** 23 * Representation of an opcode. 24 */ 25 public final class Dop { 26 /** {@code Opcodes.isValid();} the opcode value itself */ 27 private final int opcode; 28 29 /** {@code Opcodes.isValid();} the opcode family */ 30 private final int family; 31 32 /** 33 * {@code Opcodes.isValid();} what opcode (by number) to try next 34 * when attempting to match an opcode to particular arguments; 35 * {@code Opcodes.NO_NEXT} to indicate that this is the last 36 * opcode to try in a particular chain 37 */ 38 private final int nextOpcode; 39 40 /** {@code non-null;} the instruction format */ 41 private final InsnFormat format; 42 43 /** whether this opcode uses a result register */ 44 private final boolean hasResult; 45 46 /** 47 * Constructs an instance. 48 * 49 * @param opcode {@code Opcodes.isValid();} the opcode value 50 * itself 51 * @param family {@code Opcodes.isValid();} the opcode family 52 * @param nextOpcode {@code Opcodes.isValid();} what opcode (by 53 * number) to try next when attempting to match an opcode to 54 * particular arguments; {@code Opcodes.NO_NEXT} to indicate that 55 * this is the last opcode to try in a particular chain 56 * @param format {@code non-null;} the instruction format 57 * @param hasResult whether the opcode has a result register; if so it 58 * is always the first register 59 */ Dop(int opcode, int family, int nextOpcode, InsnFormat format, boolean hasResult)60 public Dop(int opcode, int family, int nextOpcode, InsnFormat format, 61 boolean hasResult) { 62 if (!Opcodes.isValidShape(opcode)) { 63 throw new IllegalArgumentException("bogus opcode"); 64 } 65 66 if (!Opcodes.isValidShape(family)) { 67 throw new IllegalArgumentException("bogus family"); 68 } 69 70 if (!Opcodes.isValidShape(nextOpcode)) { 71 throw new IllegalArgumentException("bogus nextOpcode"); 72 } 73 74 if (format == null) { 75 throw new NullPointerException("format == null"); 76 } 77 78 this.opcode = opcode; 79 this.family = family; 80 this.nextOpcode = nextOpcode; 81 this.format = format; 82 this.hasResult = hasResult; 83 } 84 85 /** {@inheritDoc} */ 86 @Override toString()87 public String toString() { 88 return getName(); 89 } 90 91 /** 92 * Gets the opcode value. 93 * 94 * @return {@code Opcodes.MIN_VALUE..Opcodes.MAX_VALUE;} the opcode value 95 */ getOpcode()96 public int getOpcode() { 97 return opcode; 98 } 99 100 /** 101 * Gets the opcode family. The opcode family is the unmarked (no 102 * "/...") opcode that has equivalent semantics to this one. 103 * 104 * @return {@code Opcodes.MIN_VALUE..Opcodes.MAX_VALUE;} the opcode family 105 */ getFamily()106 public int getFamily() { 107 return family; 108 } 109 110 /** 111 * Gets the instruction format. 112 * 113 * @return {@code non-null;} the instruction format 114 */ getFormat()115 public InsnFormat getFormat() { 116 return format; 117 } 118 119 /** 120 * Returns whether this opcode uses a result register. 121 * 122 * @return {@code true} iff this opcode uses a result register 123 */ hasResult()124 public boolean hasResult() { 125 return hasResult; 126 } 127 128 /** 129 * Gets the opcode name. 130 * 131 * @return {@code non-null;} the opcode name 132 */ getName()133 public String getName() { 134 return OpcodeInfo.getName(opcode); 135 } 136 137 /** 138 * Gets the opcode value to try next when attempting to match an 139 * opcode to particular arguments. This returns {@code 140 * Opcodes.NO_NEXT} to indicate that this is the last opcode to 141 * try in a particular chain. 142 * 143 * @return {@code Opcodes.MIN_VALUE..Opcodes.MAX_VALUE;} the opcode value 144 */ getNextOpcode()145 public int getNextOpcode() { 146 return nextOpcode; 147 } 148 149 /** 150 * Gets the opcode for the opposite test of this instance. This is only 151 * valid for opcodes which are in fact tests. 152 * 153 * @return {@code non-null;} the opposite test 154 */ getOppositeTest()155 public Dop getOppositeTest() { 156 switch (opcode) { 157 case Opcodes.IF_EQ: return Dops.IF_NE; 158 case Opcodes.IF_NE: return Dops.IF_EQ; 159 case Opcodes.IF_LT: return Dops.IF_GE; 160 case Opcodes.IF_GE: return Dops.IF_LT; 161 case Opcodes.IF_GT: return Dops.IF_LE; 162 case Opcodes.IF_LE: return Dops.IF_GT; 163 case Opcodes.IF_EQZ: return Dops.IF_NEZ; 164 case Opcodes.IF_NEZ: return Dops.IF_EQZ; 165 case Opcodes.IF_LTZ: return Dops.IF_GEZ; 166 case Opcodes.IF_GEZ: return Dops.IF_LTZ; 167 case Opcodes.IF_GTZ: return Dops.IF_LEZ; 168 case Opcodes.IF_LEZ: return Dops.IF_GTZ; 169 } 170 171 throw new IllegalArgumentException("bogus opcode: " + this); 172 } 173 } 174