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.dex.code;
18579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
19579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.code.RegisterSpec;
20579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.code.RegisterSpecList;
21579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.code.SourcePosition;
22579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.util.AnnotatedOutput;
23579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.util.Hex;
24579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.util.TwoColumnOutput;
25579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
26579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.util.BitSet;
27579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
28579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson/**
29579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Base class for Dalvik instructions.
30579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */
31579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonpublic abstract class DalvInsn {
32579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
33579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * the actual output address of this instance, if known, or
34579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * {@code -1} if not
35579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
36579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private int address;
37579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
38579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** the opcode; one of the constants from {@link Dops} */
39579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final Dop opcode;
40579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
41579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@code non-null;} source position */
42579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final SourcePosition position;
43579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
44579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@code non-null;} list of register arguments */
45579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final RegisterSpecList registers;
46579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
47579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
48579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Makes a move instruction, appropriate and ideal for the given arguments.
49579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
50579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param position {@code non-null;} source position information
51579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param dest {@code non-null;} destination register
52579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param src {@code non-null;} source register
53579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} an appropriately-constructed instance
54579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
55579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static SimpleInsn makeMove(SourcePosition position,
56579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            RegisterSpec dest, RegisterSpec src) {
57579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        boolean category1 = dest.getCategory() == 1;
58579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        boolean reference = dest.getType().isReference();
59579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int destReg = dest.getReg();
60579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int srcReg = src.getReg();
61579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Dop opcode;
62579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
63579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if ((srcReg | destReg) < 16) {
64579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            opcode = reference ? Dops.MOVE_OBJECT :
65579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                (category1 ? Dops.MOVE : Dops.MOVE_WIDE);
66579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } else if (destReg < 256) {
67579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            opcode = reference ? Dops.MOVE_OBJECT_FROM16 :
68579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                (category1 ? Dops.MOVE_FROM16 : Dops.MOVE_WIDE_FROM16);
69579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } else {
70579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            opcode = reference ? Dops.MOVE_OBJECT_16 :
71579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                (category1 ? Dops.MOVE_16 : Dops.MOVE_WIDE_16);
72579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
73579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
74579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return new SimpleInsn(opcode, position,
75579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                              RegisterSpecList.make(dest, src));
76579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
77579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
78579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
79579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Constructs an instance. The output address of this instance is initially
80579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * unknown ({@code -1}).
81579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
82579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * <p><b>Note:</b> In the unlikely event that an instruction takes
83579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * absolutely no registers (e.g., a {@code nop} or a
84579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * no-argument no-result static method call), then the given
85579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * register list may be passed as {@link
86579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * RegisterSpecList#EMPTY}.</p>
87579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
88579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param opcode the opcode; one of the constants from {@link Dops}
89579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param position {@code non-null;} source position
90579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param registers {@code non-null;} register list, including a
91579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * result register if appropriate (that is, registers may be either
92579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * ins and outs)
93579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
94579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public DalvInsn(Dop opcode, SourcePosition position,
95579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    RegisterSpecList registers) {
96579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (opcode == null) {
97579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new NullPointerException("opcode == null");
98579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
99579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
100579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (position == null) {
101579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new NullPointerException("position == null");
102579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
103579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
104579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (registers == null) {
105579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new NullPointerException("registers == null");
106579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
107579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
108579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.address = -1;
109579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.opcode = opcode;
110579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.position = position;
111579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.registers = registers;
112579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
113579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
114579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@inheritDoc} */
115579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    @Override
116579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public final String toString() {
117579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        StringBuffer sb = new StringBuffer(100);
118579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
119579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        sb.append(identifierString());
120579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        sb.append(' ');
121579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        sb.append(position);
122579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
123579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        sb.append(": ");
124579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        sb.append(opcode.getName());
125579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
126579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        boolean needComma = false;
127579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (registers.size() != 0) {
128579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            sb.append(registers.toHuman(" ", ", ", null));
129579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            needComma = true;
130579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
131579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
132579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        String extra = argString();
133579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (extra != null) {
134579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (needComma) {
135579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                sb.append(',');
136579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
137579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            sb.append(' ');
138579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            sb.append(extra);
139579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
140579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
141579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return sb.toString();
142579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
143579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
144579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
145579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets whether the address of this instruction is known.
146579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
147579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @see #getAddress
148579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @see #setAddress
149579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
150579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public final boolean hasAddress() {
151579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return (address >= 0);
152579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
153579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
154579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
155579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the output address of this instruction, if it is known. This throws
156579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * a {@code RuntimeException} if it has not yet been set.
157579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
158579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @see #setAddress
159579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
160579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code >= 0;} the output address
161579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
162579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public final int getAddress() {
163579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (address < 0) {
164579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new RuntimeException("address not yet known");
165579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
166579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
167579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return address;
168579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
169579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
170579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
171579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the opcode.
172579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
173579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the opcode
174579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
175579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public final Dop getOpcode() {
176579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return opcode;
177579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
178579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
179579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
180579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the source position.
181579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
182579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the source position
183579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
184579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public final SourcePosition getPosition() {
185579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return position;
186579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
187579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
188579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
189579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the register list for this instruction.
190579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
191579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the registers
192579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
193579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public final RegisterSpecList getRegisters() {
194579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return registers;
195579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
196579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
197579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
198579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Returns whether this instance's opcode uses a result register.
199579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * This method is a convenient shorthand for
200579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * {@code getOpcode().hasResult()}.
201579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
202579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code true} iff this opcode uses a result register
203579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
204579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public final boolean hasResult() {
205579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return opcode.hasResult();
206579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
207579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
208579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
209579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the minimum distinct registers required for this instruction.
210579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Uses the given BitSet to determine which registers require
211579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * replacement, and ignores registers that are already compatible.
212579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * This assumes that the result (if any) can share registers with the
213579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * sources (if any), that each source register is unique, and that
214579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * (to be explicit here) category-2 values take up two consecutive
215579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * registers.
216579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
217579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param compatRegs {@code non-null;} set of compatible registers
218579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code >= 0;} the minimum distinct register requirement
219579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
220579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public final int getMinimumRegisterRequirement(BitSet compatRegs) {
221579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        boolean hasResult = hasResult();
222579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int regSz = registers.size();
223579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int resultRequirement = 0;
224579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int sourceRequirement = 0;
225579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
226579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (hasResult && !compatRegs.get(0)) {
227579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            resultRequirement = registers.get(0).getCategory();
228579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
229579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
230579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (int i = hasResult ? 1 : 0; i < regSz; i++) {
231579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (!compatRegs.get(i)) {
232579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                sourceRequirement += registers.get(i).getCategory();
233579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
234579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
235579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
236579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return Math.max(sourceRequirement, resultRequirement);
237579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
238579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
239579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
240579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the instruction that is equivalent to this one, except that
241579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * it uses sequential registers starting at {@code 0} (storing
242579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * the result, if any, in register {@code 0} as well).
243579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
244579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the replacement
245579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
246579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public DalvInsn getLowRegVersion() {
247579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        RegisterSpecList regs =
248579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            registers.withExpandedRegisters(0, hasResult(), null);
249579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return withRegisters(regs);
250579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
251579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
252579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
253579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the instruction prefix required, if any, to use in an expanded
254579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * version of this instance. Will not generate moves for registers
255579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * marked compatible to the format by the given BitSet.
256579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
257579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @see #expandedVersion
258579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
259579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param compatRegs {@code non-null;} set of compatible registers
260579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code null-ok;} the prefix, if any
261579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
262579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public DalvInsn expandedPrefix(BitSet compatRegs) {
263579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        RegisterSpecList regs = registers;
264579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        boolean firstBit = compatRegs.get(0);
265579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
266579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (hasResult()) compatRegs.set(0);
267579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
268579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        regs = regs.subset(compatRegs);
269579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
270579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (hasResult()) compatRegs.set(0, firstBit);
271579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
272579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (regs.size() == 0) return null;
273579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
274579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return new HighRegisterPrefix(position, regs);
275579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
276579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
277579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
278579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the instruction suffix required, if any, to use in an expanded
279579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * version of this instance. Will not generate a move for a register
280579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * marked compatible to the format by the given BitSet.
281579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
282579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @see #expandedVersion
283579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
284579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param compatRegs {@code non-null;} set of compatible registers
285579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code null-ok;} the suffix, if any
286579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
287579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public DalvInsn expandedSuffix(BitSet compatRegs) {
288579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (hasResult() && !compatRegs.get(0)) {
289579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            RegisterSpec r = registers.get(0);
290579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return makeMove(position, r, r.withReg(0));
291579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } else {
292579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return null;
293579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
294579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
295579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
296579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
297579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the instruction that is equivalent to this one, except that
298579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * it replaces incompatible registers with sequential registers
299579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * starting at {@code 0} (storing the result, if any, in register
300579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * {@code 0} as well). The sequence of instructions from
301579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * {@link #expandedPrefix} and {@link #expandedSuffix} (if non-null)
302579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * surrounding the result of a call to this method are the expanded
303579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * transformation of this instance, and it is guaranteed that the
304579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * number of low registers used will be the number returned by
305579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * {@link #getMinimumRegisterRequirement}.
306579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
307579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param compatRegs {@code non-null;} set of compatible registers
308579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the replacement
309579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
310579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public DalvInsn expandedVersion(BitSet compatRegs) {
311579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        RegisterSpecList regs =
312579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            registers.withExpandedRegisters(0, hasResult(), compatRegs);
313579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return withRegisters(regs);
314579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
315579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
316579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
317579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the short identifier for this instruction. This is its
318579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * address, if assigned, or its identity hashcode if not.
319579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
320579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the identifier
321579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
322579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public final String identifierString() {
323579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (address != -1) {
324579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return String.format("%04x", address);
325579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
326579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
327579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return Hex.u4(System.identityHashCode(this));
328579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
329579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
330579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
331579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Returns the string form of this instance suitable for inclusion in
332579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * a human-oriented listing dump. This method will return {@code null}
333579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * if this instance should not appear in a listing.
334579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
335579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param prefix {@code non-null;} prefix before the address; each follow-on
336579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * line will be indented to match as well
337579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param width {@code >= 0;} the width of the output or {@code 0} for
338579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * unlimited width
339579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param noteIndices whether to include an explicit notation of
340579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * constant pool indices
341579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code null-ok;} the string form or {@code null} if this
342579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * instance should not appear in a listing
343579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
344579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public final String listingString(String prefix, int width,
345579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            boolean noteIndices) {
346579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        String insnPerSe = listingString0(noteIndices);
347579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
348579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (insnPerSe == null) {
349579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return null;
350579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
351579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
352579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        String addr = prefix + identifierString() + ": ";
353579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int w1 = addr.length();
354579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int w2 = (width == 0) ? insnPerSe.length() : (width - w1);
355579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
356579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return TwoColumnOutput.toString(addr, w1, "", insnPerSe, w2);
357579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
358579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
359579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
360579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Sets the output address.
361579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
362579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param address {@code >= 0;} the output address
363579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
364579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public final void setAddress(int address) {
365579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (address < 0) {
366579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new IllegalArgumentException("address < 0");
367579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
368579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
369579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.address = address;
370579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
371579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
372579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
373579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the address immediately after this instance. This is only
374579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * calculable if this instance's address is known, and it is equal
375579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * to the address plus the length of the instruction format of this
376579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * instance's opcode.
377579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
378579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code >= 0;} the next address
379579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
380579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public final int getNextAddress() {
381579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return getAddress() + codeSize();
382579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
383579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
384579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
385579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the size of this instruction, in 16-bit code units.
386579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
387579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code >= 0;} the code size of this instruction
388579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
389579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public abstract int codeSize();
390579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
391579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
392579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Writes this instance to the given output. This method should
393579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * never annotate the output.
394579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
395579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param out {@code non-null;} where to write to
396579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
397579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public abstract void writeTo(AnnotatedOutput out);
398579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
399579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
400579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Returns an instance that is just like this one, except that its
401579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * opcode is replaced by the one given, and its address is reset.
402579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
403579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param opcode {@code non-null;} the new opcode
404579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} an appropriately-constructed instance
405579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
406579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public abstract DalvInsn withOpcode(Dop opcode);
407579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
408579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
409579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Returns an instance that is just like this one, except that all
410579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * register references have been offset by the given delta, and its
411579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * address is reset.
412579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
413579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param delta the amount to offset register references by
414579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} an appropriately-constructed instance
415579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
416579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public abstract DalvInsn withRegisterOffset(int delta);
417579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
418579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
419579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Returns an instance that is just like this one, except that the
420579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * register list is replaced by the given one, and its address is
421579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * reset.
422579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
423579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param registers {@code non-null;} new register list
424579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} an appropriately-constructed instance
425579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
426579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public abstract DalvInsn withRegisters(RegisterSpecList registers);
427579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
428579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
429579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the string form for any arguments to this instance. Subclasses
430579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * must override this.
431579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
432579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code null-ok;} the string version of any arguments or
433579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * {@code null} if there are none
434579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
435579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    protected abstract String argString();
436579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
437579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
438579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Helper for {@link #listingString}, which returns the string
439579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * form of this instance suitable for inclusion in a
440579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * human-oriented listing dump, not including the instruction
441579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * address and without respect for any output formatting. This
442579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * method should return {@code null} if this instance should
443579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * not appear in a listing.
444579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
445579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param noteIndices whether to include an explicit notation of
446579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * constant pool indices
447579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code null-ok;} the listing string
448579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
449579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    protected abstract String listingString0(boolean noteIndices);
450579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson}
451