com.android.dx.rop.code.Rop Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of builder Show documentation
Show all versions of builder Show documentation
Library to build Android applications.
/*
* 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.rop.code;
import com.android.dx.rop.type.StdTypeList;
import com.android.dx.rop.type.Type;
import com.android.dx.rop.type.TypeList;
import com.android.dx.util.Hex;
/**
* Class that describes all the immutable parts of register-based operations.
*/
public final class Rop {
/** minimum {@code BRANCH_*} value */
public static final int BRANCH_MIN = 1;
/** indicates a non-branching op */
public static final int BRANCH_NONE = 1;
/** indicates a function/method return */
public static final int BRANCH_RETURN = 2;
/** indicates an unconditional goto */
public static final int BRANCH_GOTO = 3;
/** indicates a two-way branch */
public static final int BRANCH_IF = 4;
/** indicates a switch-style branch */
public static final int BRANCH_SWITCH = 5;
/** indicates a throw-style branch (both always-throws and may-throw) */
public static final int BRANCH_THROW = 6;
/** maximum {@code BRANCH_*} value */
public static final int BRANCH_MAX = 6;
/** the opcode; one of the constants in {@link RegOps} */
private final int opcode;
/**
* {@code non-null;} result type of this operation; {@link Type#VOID} for
* no-result operations
*/
private final Type result;
/** {@code non-null;} types of all the sources of this operation */
private final TypeList sources;
/** {@code non-null;} list of possible types thrown by this operation */
private final TypeList exceptions;
/**
* the branchingness of this op; one of the {@code BRANCH_*}
* constants in this class
*/
private final int branchingness;
/** whether this is a function/method call op or similar */
private final boolean isCallLike;
/** {@code null-ok;} nickname, if specified (used for debugging) */
private final String nickname;
/**
* Constructs an instance. This method is private. Use one of the
* public constructors.
*
* @param opcode the opcode; one of the constants in {@link RegOps}
* @param result {@code non-null;} result type of this operation; {@link
* Type#VOID} for no-result operations
* @param sources {@code non-null;} types of all the sources of this operation
* @param exceptions {@code non-null;} list of possible types thrown by this
* operation
* @param branchingness the branchingness of this op; one of the
* {@code BRANCH_*} constants
* @param isCallLike whether the op is a function/method call or similar
* @param nickname {@code null-ok;} optional nickname (used for debugging)
*/
public Rop(int opcode, Type result, TypeList sources,
TypeList exceptions, int branchingness, boolean isCallLike,
String nickname) {
if (result == null) {
throw new NullPointerException("result == null");
}
if (sources == null) {
throw new NullPointerException("sources == null");
}
if (exceptions == null) {
throw new NullPointerException("exceptions == null");
}
if ((branchingness < BRANCH_MIN) || (branchingness > BRANCH_MAX)) {
throw new IllegalArgumentException("bogus branchingness");
}
if ((exceptions.size() != 0) && (branchingness != BRANCH_THROW)) {
throw new IllegalArgumentException("exceptions / branchingness " +
"mismatch");
}
this.opcode = opcode;
this.result = result;
this.sources = sources;
this.exceptions = exceptions;
this.branchingness = branchingness;
this.isCallLike = isCallLike;
this.nickname = nickname;
}
/**
* Constructs an instance. The constructed instance is never a
* call-like op (see {@link #isCallLike}).
*
* @param opcode the opcode; one of the constants in {@link RegOps}
* @param result {@code non-null;} result type of this operation; {@link
* Type#VOID} for no-result operations
* @param sources {@code non-null;} types of all the sources of this operation
* @param exceptions {@code non-null;} list of possible types thrown by this
* operation
* @param branchingness the branchingness of this op; one of the
* {@code BRANCH_*} constants
* @param nickname {@code null-ok;} optional nickname (used for debugging)
*/
public Rop(int opcode, Type result, TypeList sources,
TypeList exceptions, int branchingness, String nickname) {
this(opcode, result, sources, exceptions, branchingness, false,
nickname);
}
/**
* Constructs a no-exception instance. The constructed instance is never a
* call-like op (see {@link #isCallLike}).
*
* @param opcode the opcode; one of the constants in {@link RegOps}
* @param result {@code non-null;} result type of this operation; {@link
* Type#VOID} for no-result operations
* @param sources {@code non-null;} types of all the sources of this operation
* @param branchingness the branchingness of this op; one of the
* {@code BRANCH_*} constants
* @param nickname {@code null-ok;} optional nickname (used for debugging)
*/
public Rop(int opcode, Type result, TypeList sources, int branchingness,
String nickname) {
this(opcode, result, sources, StdTypeList.EMPTY, branchingness, false,
nickname);
}
/**
* Constructs a non-branching no-exception instance. The
* {@code branchingness} is always {@code BRANCH_NONE},
* and it is never a call-like op (see {@link #isCallLike}).
*
* @param opcode the opcode; one of the constants in {@link RegOps}
* @param result {@code non-null;} result type of this operation; {@link
* Type#VOID} for no-result operations
* @param sources {@code non-null;} types of all the sources of this operation
* @param nickname {@code null-ok;} optional nickname (used for debugging)
*/
public Rop(int opcode, Type result, TypeList sources, String nickname) {
this(opcode, result, sources, StdTypeList.EMPTY, Rop.BRANCH_NONE,
false, nickname);
}
/**
* Constructs a non-empty exceptions instance. Its
* {@code branchingness} is always {@code BRANCH_THROW},
* but it is never a call-like op (see {@link #isCallLike}).
*
* @param opcode the opcode; one of the constants in {@link RegOps}
* @param result {@code non-null;} result type of this operation; {@link
* Type#VOID} for no-result operations
* @param sources {@code non-null;} types of all the sources of this operation
* @param exceptions {@code non-null;} list of possible types thrown by this
* operation
* @param nickname {@code null-ok;} optional nickname (used for debugging)
*/
public Rop(int opcode, Type result, TypeList sources, TypeList exceptions,
String nickname) {
this(opcode, result, sources, exceptions, Rop.BRANCH_THROW, false,
nickname);
}
/**
* Constructs a non-nicknamed instance with non-empty exceptions, which
* is always a call-like op (see {@link #isCallLike}). Its
* {@code branchingness} is always {@code BRANCH_THROW}.
*
* @param opcode the opcode; one of the constants in {@link RegOps}
* @param sources {@code non-null;} types of all the sources of this operation
* @param exceptions {@code non-null;} list of possible types thrown by this
* operation
*/
public Rop(int opcode, TypeList sources, TypeList exceptions) {
this(opcode, Type.VOID, sources, exceptions, Rop.BRANCH_THROW, true,
null);
}
/** {@inheritDoc} */
@Override
public boolean equals(Object other) {
if (this == other) {
// Easy out.
return true;
}
if (!(other instanceof Rop)) {
return false;
}
Rop rop = (Rop) other;
return (opcode == rop.opcode) &&
(branchingness == rop.branchingness) &&
(result == rop.result) &&
sources.equals(rop.sources) &&
exceptions.equals(rop.exceptions);
}
/** {@inheritDoc} */
@Override
public int hashCode() {
int h = (opcode * 31) + branchingness;
h = (h * 31) + result.hashCode();
h = (h * 31) + sources.hashCode();
h = (h * 31) + exceptions.hashCode();
return h;
}
/** {@inheritDoc} */
@Override
public String toString() {
StringBuffer sb = new StringBuffer(40);
sb.append("Rop{");
sb.append(RegOps.opName(opcode));
if (result != Type.VOID) {
sb.append(" ");
sb.append(result);
} else {
sb.append(" .");
}
sb.append(" <-");
int sz = sources.size();
if (sz == 0) {
sb.append(" .");
} else {
for (int i = 0; i < sz; i++) {
sb.append(' ');
sb.append(sources.getType(i));
}
}
if (isCallLike) {
sb.append(" call");
}
sz = exceptions.size();
if (sz != 0) {
sb.append(" throws");
for (int i = 0; i < sz; i++) {
sb.append(' ');
Type one = exceptions.getType(i);
if (one == Type.THROWABLE) {
sb.append("");
} else {
sb.append(exceptions.getType(i));
}
}
} else {
switch (branchingness) {
case BRANCH_NONE: sb.append(" flows"); break;
case BRANCH_RETURN: sb.append(" returns"); break;
case BRANCH_GOTO: sb.append(" gotos"); break;
case BRANCH_IF: sb.append(" ifs"); break;
case BRANCH_SWITCH: sb.append(" switches"); break;
default: sb.append(" " + Hex.u1(branchingness)); break;
}
}
sb.append('}');
return sb.toString();
}
/**
* Gets the opcode.
*
* @return the opcode
*/
public int getOpcode() {
return opcode;
}
/**
* Gets the result type. A return value of {@link Type#VOID}
* means this operation returns nothing.
*
* @return {@code null-ok;} the result spec
*/
public Type getResult() {
return result;
}
/**
* Gets the source types.
*
* @return {@code non-null;} the source types
*/
public TypeList getSources() {
return sources;
}
/**
* Gets the list of exception types that might be thrown.
*
* @return {@code non-null;} the list of exception types
*/
public TypeList getExceptions() {
return exceptions;
}
/**
* Gets the branchingness of this instance.
*
* @return the branchingness
*/
public int getBranchingness() {
return branchingness;
}
/**
* Gets whether this opcode is a function/method call or similar.
*
* @return {@code true} iff this opcode is call-like
*/
public boolean isCallLike() {
return isCallLike;
}
/**
* Gets whether this opcode is commutative (the order of its sources are
* unimportant) or not. All commutative Rops have exactly two sources and
* have no branchiness.
*
* @return true if rop is commutative
*/
public boolean isCommutative() {
switch (opcode) {
case RegOps.AND:
case RegOps.OR:
case RegOps.XOR:
case RegOps.ADD:
case RegOps.MUL:
return true;
default:
return false;
}
}
/**
* Gets the nickname. If this instance has no nickname, this returns
* the result of calling {@link #toString}.
*
* @return {@code non-null;} the nickname
*/
public String getNickname() {
if (nickname != null) {
return nickname;
}
return toString();
}
/**
* Gets whether this operation can possibly throw an exception. This
* is just a convenient wrapper for
* {@code getExceptions().size() != 0}.
*
* @return {@code true} iff this operation can possibly throw
*/
public final boolean canThrow() {
return (exceptions.size() != 0);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy