1579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson/*
2579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Copyright (C) 2007 The Android Open Source Project
3579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
4579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Licensed under the Apache License, Version 2.0 (the "License");
5579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * you may not use this file except in compliance with the License.
6579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * You may obtain a copy of the License at
7579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
8579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *      http://www.apache.org/licenses/LICENSE-2.0
9579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
10579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Unless required by applicable law or agreed to in writing, software
11579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS,
12579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * See the License for the specific language governing permissions and
14579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * limitations under the License.
15579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */
16579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
17579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonpackage com.android.dx.rop.code;
18579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
19579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.type.StdTypeList;
20579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.type.Type;
21579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.type.TypeList;
22579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.util.ToHuman;
23579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
24579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson/**
25579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * A register-based instruction. An instruction is the combination of
26579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * an opcode (which specifies operation and source/result types), a
27579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * list of actual sources and result registers/values, and additional
28579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * information.
29579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */
30579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonpublic abstract class Insn implements ToHuman {
31579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@code non-null;} opcode */
32579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final Rop opcode;
33579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
34579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@code non-null;} source position */
35579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final SourcePosition position;
36579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
37579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@code null-ok;} spec for the result of this instruction, if any */
38579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final RegisterSpec result;
39579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
40579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@code non-null;} specs for all the sources of this instruction */
41579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final RegisterSpecList sources;
42579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
43579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
44579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Constructs an instance.
45579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
46579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param opcode {@code non-null;} the opcode
47579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param position {@code non-null;} source position
48579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param result {@code null-ok;} spec for the result, if any
49579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param sources {@code non-null;} specs for all the sources
50579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
51579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public Insn(Rop opcode, SourcePosition position, RegisterSpec result,
52579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                RegisterSpecList sources) {
53579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (opcode == null) {
54579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new NullPointerException("opcode == null");
55579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
56579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
57579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (position == null) {
58579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new NullPointerException("position == null");
59579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
60579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
61579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (sources == null) {
62579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new NullPointerException("sources == null");
63579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
64579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
65579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.opcode = opcode;
66579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.position = position;
67579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.result = result;
68579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.sources = sources;
69579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
70579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
71579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
72579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * {@inheritDoc}
73579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
74579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Instances of this class compare by identity. That is,
75579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * {@code x.equals(y)} is only true if {@code x == y}.
76579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
77579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    @Override
78579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public final boolean equals(Object other) {
79579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return (this == other);
80579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
81579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
82579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
83579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * {@inheritDoc}
84579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
85579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * This implementation returns the identity hashcode of this
86579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * instance. This is proper, since instances of this class compare
87579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * by identity (see {@link #equals}).
88579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
89579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    @Override
90579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public final int hashCode() {
91579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return System.identityHashCode(this);
92579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
93579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
94579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@inheritDoc} */
95579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    @Override
96579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public String toString() {
97579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return toStringWithInline(getInlineString());
98579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
99579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
100579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
101579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets a human-oriented (and slightly lossy) string for this instance.
102579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
103579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the human string form
104579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
105579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public String toHuman() {
106579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return toHumanWithInline(getInlineString());
107579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
108579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
109579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
110579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets an "inline" string portion for toHuman(), if available. This
111579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * is the portion that appears after the Rop opcode
112579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
113579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code null-ok;} if non-null, the inline text for toHuman()
114579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
115579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public String getInlineString() {
116579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return null;
117579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
118579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
119579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
120579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the opcode.
121579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
122579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the opcode
123579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
124579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public final Rop getOpcode() {
125579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return opcode;
126579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
127579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
128579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
129579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the source position.
130579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
131579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the source position
132579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
133579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public final SourcePosition getPosition() {
134579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return position;
135579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
136579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
137579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
138579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the result spec, if any. A return value of {@code null}
139579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * means this instruction returns nothing.
140579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
141579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code null-ok;} the result spec, if any
142579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
143579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public final RegisterSpec getResult() {
144579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return result;
145579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
146579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
147579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
148579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the spec of a local variable assignment that occurs at this
149579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * instruction, or null if no local variable assignment occurs. This
150579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * may be the result register, or for {@code mark-local} insns
151579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * it may be the source.
152579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
153579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code null-ok;} a named register spec or null
154579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
155579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public final RegisterSpec getLocalAssignment() {
156579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        RegisterSpec assignment;
157579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (opcode.getOpcode() == RegOps.MARK_LOCAL) {
158579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            assignment = sources.get(0);
159579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } else {
160579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            assignment = result;
161579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
162579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
163579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (assignment == null) {
164579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return null;
165579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
166579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
167579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        LocalItem localItem = assignment.getLocalItem();
168579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
169579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (localItem == null) {
170579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return null;
171579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
172579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
173579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return assignment;
174579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
175579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
176579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
177579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the source specs.
178579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
179579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the source specs
180579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
181579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public final RegisterSpecList getSources() {
182579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return sources;
183579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
184579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
185579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
186579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets whether this instruction can possibly throw an exception. This
187579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * is just a convenient wrapper for {@code getOpcode().canThrow()}.
188579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
189579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code true} iff this instruction can possibly throw
190579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
191579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public final boolean canThrow() {
192579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return opcode.canThrow();
193579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
194579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
195579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
196579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the list of possibly-caught exceptions. This returns {@link
197579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * StdTypeList#EMPTY} if this instruction has no handlers,
198579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * which can be <i>either</i> if this instruction can't possibly
199579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * throw or if it merely doesn't handle any of its possible
200579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * exceptions. To determine whether this instruction can throw,
201579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * use {@link #canThrow}.
202579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
203579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the catches list
204579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
205579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public abstract TypeList getCatches();
206579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
207579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
208579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Calls the appropriate method on the given visitor, depending on the
209579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * class of this instance. Subclasses must override this.
210579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
211579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param visitor {@code non-null;} the visitor to call on
212579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
213579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public abstract void accept(Visitor visitor);
214579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
215579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
216579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Returns an instance that is just like this one, except that it
217579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * has a catch list with the given item appended to the end. This
218579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * method throws an exception if this instance can't possibly
219579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * throw. To determine whether this instruction can throw, use
220579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * {@link #canThrow}.
221579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
222579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param type {@code non-null;} type to append to the catch list
223579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} an appropriately-constructed instance
224579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
225579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public abstract Insn withAddedCatch(Type type);
226579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
227579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
228579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Returns an instance that is just like this one, except that all
229579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * register references have been offset by the given delta.
230579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
231579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param delta the amount to offset register references by
232579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} an appropriately-constructed instance
233579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
234579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public abstract Insn withRegisterOffset(int delta);
235579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
236579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
237579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Returns an instance that is just like this one, except that, if
238579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * possible, the insn is converted into a version in which a source
239579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * (if it is a constant) is represented directly rather than as a
240579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * register reference. {@code this} is returned in cases where the
241579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * translation is not possible.
242579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
243579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} an appropriately-constructed instance
244579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
245579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public Insn withSourceLiteral() {
246579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return this;
247579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
248579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
249579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
250579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Returns an exact copy of this Insn
251579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
252579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} an appropriately-constructed instance
253579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
254579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public Insn copy() {
255579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return withRegisterOffset(0);
256579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
257579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
258579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
259579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
260579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Compares, handling nulls safely
261579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
262579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param a first object
263579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param b second object
264579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return true if they're equal or both null.
265579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
266579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private static boolean equalsHandleNulls (Object a, Object b) {
267579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return (a == b) || ((a != null) && a.equals(b));
268579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
269579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
270579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
271579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Compares Insn contents, since {@code Insn.equals()} is defined
272579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * to be an identity compare. Insn's are {@code contentEquals()}
273579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * if they have the same opcode, registers, source position, and other
274579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * metadata.
275579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
276579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return true in the case described above
277579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
278579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public boolean contentEquals(Insn b) {
279579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return opcode == b.getOpcode()
280579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                && position.equals(b.getPosition())
281579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                && (getClass() == b.getClass())
282579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                && equalsHandleNulls(result, b.getResult())
283579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                && equalsHandleNulls(sources, b.getSources())
284579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                && StdTypeList.equalContents(getCatches(), b.getCatches());
285579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
286579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
287579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
288579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Returns an instance that is just like this one, except
289579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * with new result and source registers.
290579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
291579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param result {@code null-ok;} new result register
292579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param sources {@code non-null;} new sources registers
293579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} an appropriately-constructed instance
294579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
295579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public abstract Insn withNewRegisters(RegisterSpec result,
296579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            RegisterSpecList sources);
297579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
298579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
299579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Returns the string form of this instance, with the given bit added in
300579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * the standard location for an inline argument.
301579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
302579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param extra {@code null-ok;} the inline argument string
303579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the string form
304579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
305579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    protected final String toStringWithInline(String extra) {
306579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        StringBuffer sb = new StringBuffer(80);
307579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
308579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        sb.append("Insn{");
309579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        sb.append(position);
310579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        sb.append(' ');
311579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        sb.append(opcode);
312579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
313579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (extra != null) {
314579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            sb.append(' ');
315579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            sb.append(extra);
316579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
317579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
318579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        sb.append(" :: ");
319579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
320579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (result != null) {
321579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            sb.append(result);
322579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            sb.append(" <- ");
323579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
324579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
325579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        sb.append(sources);
326579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        sb.append('}');
327579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
328579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return sb.toString();
329579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
330579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
331579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
332579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Returns the human string form of this instance, with the given
333579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * bit added in the standard location for an inline argument.
334579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
335579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param extra {@code null-ok;} the inline argument string
336579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the human string form
337579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
338579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    protected final String toHumanWithInline(String extra) {
339579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        StringBuffer sb = new StringBuffer(80);
340579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
341579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        sb.append(position);
342579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        sb.append(": ");
343579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        sb.append(opcode.getNickname());
344579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
345579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (extra != null) {
346579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            sb.append("(");
347579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            sb.append(extra);
348579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            sb.append(")");
349579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
350579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
351579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (result == null) {
352579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            sb.append(" .");
353579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } else {
354579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            sb.append(" ");
355579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            sb.append(result.toHuman());
356579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
357579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
358579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        sb.append(" <-");
359579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
360579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int sz = sources.size();
361579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (sz == 0) {
362579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            sb.append(" .");
363579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } else {
364579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            for (int i = 0; i < sz; i++) {
365579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                sb.append(" ");
366579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                sb.append(sources.get(i).toHuman());
367579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
368579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
369579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
370579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return sb.toString();
371579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
372579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
373579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
374579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
375579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Visitor interface for this (outer) class.
376579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
377579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static interface Visitor {
378579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /**
379579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * Visits a {@link PlainInsn}.
380579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *
381579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @param insn {@code non-null;} the instruction to visit
382579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
383579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public void visitPlainInsn(PlainInsn insn);
384579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
385579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /**
386579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * Visits a {@link PlainCstInsn}.
387579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *
388579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @param insn {@code non-null;} the instruction to visit
389579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
390579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public void visitPlainCstInsn(PlainCstInsn insn);
391579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
392579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /**
393579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * Visits a {@link SwitchInsn}.
394579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *
395579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @param insn {@code non-null;} the instruction to visit
396579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
397579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public void visitSwitchInsn(SwitchInsn insn);
398579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
399579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /**
400579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * Visits a {@link ThrowingCstInsn}.
401579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *
402579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @param insn {@code non-null;} the instruction to visit
403579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
404579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public void visitThrowingCstInsn(ThrowingCstInsn insn);
405579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
406579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /**
407579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * Visits a {@link ThrowingInsn}.
408579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *
409579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @param insn {@code non-null;} the instruction to visit
410579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
411579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public void visitThrowingInsn(ThrowingInsn insn);
412579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
413579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /**
414579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * Visits a {@link FillArrayDataInsn}.
415579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *
416579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @param insn {@code non-null;} the instruction to visit
417579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
418579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public void visitFillArrayDataInsn(FillArrayDataInsn insn);
419579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
420579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
421579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
422579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Base implementation of {@link Visitor}, which has empty method
423579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * bodies for all methods.
424579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
425579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class BaseVisitor implements Visitor {
426579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /** {@inheritDoc} */
427579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public void visitPlainInsn(PlainInsn insn) {
428579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            // This space intentionally left blank.
429579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
430579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
431579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /** {@inheritDoc} */
432579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public void visitPlainCstInsn(PlainCstInsn insn) {
433579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            // This space intentionally left blank.
434579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
435579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
436579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /** {@inheritDoc} */
437579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public void visitSwitchInsn(SwitchInsn insn) {
438579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            // This space intentionally left blank.
439579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
440579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
441579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /** {@inheritDoc} */
442579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public void visitThrowingCstInsn(ThrowingCstInsn insn) {
443579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            // This space intentionally left blank.
444579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
445579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
446579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /** {@inheritDoc} */
447579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public void visitThrowingInsn(ThrowingInsn insn) {
448579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            // This space intentionally left blank.
449579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
450579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
451579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /** {@inheritDoc} */
452579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public void visitFillArrayDataInsn(FillArrayDataInsn insn) {
453579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            // This space intentionally left blank.
454579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
455579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
456579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson}
457