Dop.java revision 579d7739c53a2707ad711a2d2cae46d7d782f061
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
17package com.android.dx.dex.code;
18
19import com.android.dx.io.OpcodeInfo;
20import com.android.dx.io.Opcodes;
21
22/**
23 * Representation of an opcode.
24 */
25public 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     */
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
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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