/* * 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.io.OpcodeInfo; import com.android.dx.io.Opcodes; /** * Representation of an opcode. */ public final class Dop { /** {@code Opcodes.isValid();} the opcode value itself */ private final int opcode; /** {@code Opcodes.isValid();} the opcode family */ private final int family; /** * {@code Opcodes.isValid();} what opcode (by number) to try next * when attempting to match an opcode to particular arguments; * {@code Opcodes.NO_NEXT} to indicate that this is the last * opcode to try in a particular chain */ private final int nextOpcode; /** {@code non-null;} the instruction format */ private final InsnFormat format; /** whether this opcode uses a result register */ private final boolean hasResult; /** * Constructs an instance. * * @param opcode {@code Opcodes.isValid();} the opcode value * itself * @param family {@code Opcodes.isValid();} the opcode family * @param nextOpcode {@code Opcodes.isValid();} what opcode (by * number) to try next when attempting to match an opcode to * particular arguments; {@code Opcodes.NO_NEXT} to indicate that * this is the last opcode to try in a particular chain * @param format {@code non-null;} the instruction format * @param hasResult whether the opcode has a result register; if so it * is always the first register */ public Dop(int opcode, int family, int nextOpcode, InsnFormat format, boolean hasResult) { if (!Opcodes.isValidShape(opcode)) { throw new IllegalArgumentException("bogus opcode"); } if (!Opcodes.isValidShape(family)) { throw new IllegalArgumentException("bogus family"); } if (!Opcodes.isValidShape(nextOpcode)) { throw new IllegalArgumentException("bogus nextOpcode"); } if (format == null) { throw new NullPointerException("format == null"); } this.opcode = opcode; this.family = family; this.nextOpcode = nextOpcode; this.format = format; this.hasResult = hasResult; } /** {@inheritDoc} */ @Override public String toString() { return getName(); } /** * Gets the opcode value. * * @return {@code Opcodes.MIN_VALUE..Opcodes.MAX_VALUE;} the opcode value */ public int getOpcode() { return opcode; } /** * Gets the opcode family. The opcode family is the unmarked (no * "/...") opcode that has equivalent semantics to this one. * * @return {@code Opcodes.MIN_VALUE..Opcodes.MAX_VALUE;} the opcode family */ public int getFamily() { return family; } /** * Gets the instruction format. * * @return {@code non-null;} the instruction format */ public InsnFormat getFormat() { return format; } /** * Returns whether this opcode uses a result register. * * @return {@code true} iff this opcode uses a result register */ public boolean hasResult() { return hasResult; } /** * Gets the opcode name. * * @return {@code non-null;} the opcode name */ public String getName() { return OpcodeInfo.getName(opcode); } /** * Gets the opcode value to try next when attempting to match an * opcode to particular arguments. This returns {@code * Opcodes.NO_NEXT} to indicate that this is the last opcode to * try in a particular chain. * * @return {@code Opcodes.MIN_VALUE..Opcodes.MAX_VALUE;} the opcode value */ public int getNextOpcode() { return nextOpcode; } /** * Gets the opcode for the opposite test of this instance. This is only * valid for opcodes which are in fact tests. * * @return {@code non-null;} the opposite test */ public Dop getOppositeTest() { switch (opcode) { case Opcodes.IF_EQ: return Dops.IF_NE; case Opcodes.IF_NE: return Dops.IF_EQ; case Opcodes.IF_LT: return Dops.IF_GE; case Opcodes.IF_GE: return Dops.IF_LT; case Opcodes.IF_GT: return Dops.IF_LE; case Opcodes.IF_LE: return Dops.IF_GT; case Opcodes.IF_EQZ: return Dops.IF_NEZ; case Opcodes.IF_NEZ: return Dops.IF_EQZ; case Opcodes.IF_LTZ: return Dops.IF_GEZ; case Opcodes.IF_GEZ: return Dops.IF_LTZ; case Opcodes.IF_GTZ: return Dops.IF_LEZ; case Opcodes.IF_LEZ: return Dops.IF_GTZ; } throw new IllegalArgumentException("bogus opcode: " + this); } }