blob: 0a0cbc2855f421ad93cb42ef1fdbae52ddf6eb8d [file] [log] [blame]
/*
* 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.jack.dx.dex.code;
import com.android.jack.dx.io.OpcodeInfo;
import com.android.jack.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);
}
}