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