136836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com/*
236836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * [The "BSD licence"]
300fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * Copyright (c) 2010 Ben Gruver (JesusFreke)
436836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * All rights reserved.
536836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com *
636836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * Redistribution and use in source and binary forms, with or without
736836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * modification, are permitted provided that the following conditions
836836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * are met:
936836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * 1. Redistributions of source code must retain the above copyright
1036836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com *    notice, this list of conditions and the following disclaimer.
1136836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * 2. Redistributions in binary form must reproduce the above copyright
1236836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com *    notice, this list of conditions and the following disclaimer in the
1336836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com *    documentation and/or other materials provided with the distribution.
1436836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * 3. The name of the author may not be used to endorse or promote products
1536836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com *    derived from this software without specific prior written permission.
1636836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com *
1736836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1836836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1936836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2036836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2136836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2236836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2336836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2436836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2536836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2636836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2736836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com */
2836836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com
296ef13753e78bb7abc7e7683d5e533c3395d4a9b6JesusFreke@JesusFreke.compackage org.jf.baksmali.Adaptors;
3036836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com
31d1662b67fecaf835227aff3a136949a2358ccd4eBen Gruverimport com.google.common.collect.ImmutableList;
32bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruverimport com.google.common.collect.Lists;
33754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruverimport org.jf.baksmali.Adaptors.Debug.DebugMethodItem;
34fbea4e751fa6f1748ded4379a4b64601cb53ba7bJesusFreke@JesusFreke.comimport org.jf.baksmali.Adaptors.Format.InstructionMethodItemFactory;
355a5eafb818cc18baeef8bdae1940401da3735f25Ben Gruverimport org.jf.baksmali.BaksmaliOptions;
36754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruverimport org.jf.dexlib2.AccessFlags;
37c91b03ba45ccacfa7b0ad52592a42e8fd8c18da1Ben Gruverimport org.jf.dexlib2.Format;
38754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruverimport org.jf.dexlib2.Opcode;
392b8845bb247e3e5ee154966866b53fa9887e2609Ben Gruverimport org.jf.dexlib2.ReferenceType;
40c91b03ba45ccacfa7b0ad52592a42e8fd8c18da1Ben Gruverimport org.jf.dexlib2.analysis.AnalysisException;
41c91b03ba45ccacfa7b0ad52592a42e8fd8c18da1Ben Gruverimport org.jf.dexlib2.analysis.AnalyzedInstruction;
42c91b03ba45ccacfa7b0ad52592a42e8fd8c18da1Ben Gruverimport org.jf.dexlib2.analysis.MethodAnalyzer;
434f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruverimport org.jf.dexlib2.dexbacked.DexBackedDexFile.InvalidItemIndex;
44754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruverimport org.jf.dexlib2.iface.*;
45754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruverimport org.jf.dexlib2.iface.debug.DebugItem;
46754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruverimport org.jf.dexlib2.iface.instruction.Instruction;
47754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruverimport org.jf.dexlib2.iface.instruction.OffsetInstruction;
482b8845bb247e3e5ee154966866b53fa9887e2609Ben Gruverimport org.jf.dexlib2.iface.instruction.ReferenceInstruction;
49bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruverimport org.jf.dexlib2.iface.instruction.formats.Instruction31t;
502b8845bb247e3e5ee154966866b53fa9887e2609Ben Gruverimport org.jf.dexlib2.iface.reference.MethodReference;
51bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruverimport org.jf.dexlib2.immutable.instruction.ImmutableInstruction31t;
52ffe82bdcb5c914b3a60b630c6d3abe6fc9229decBen Gruverimport org.jf.dexlib2.util.InstructionOffsetMap;
534f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruverimport org.jf.dexlib2.util.InstructionOffsetMap.InvalidInstructionOffset;
54ffe82bdcb5c914b3a60b630c6d3abe6fc9229decBen Gruverimport org.jf.dexlib2.util.ReferenceUtil;
55ffe82bdcb5c914b3a60b630c6d3abe6fc9229decBen Gruverimport org.jf.dexlib2.util.SyntheticAccessorResolver;
56bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruverimport org.jf.dexlib2.util.SyntheticAccessorResolver.AccessedMember;
57ffe82bdcb5c914b3a60b630c6d3abe6fc9229decBen Gruverimport org.jf.dexlib2.util.TypeUtils;
58bf95959ae43ddd003936a01dfaecc612a438d4b5Ben Gruverimport org.jf.util.ExceptionWithContext;
59ffe82bdcb5c914b3a60b630c6d3abe6fc9229decBen Gruverimport org.jf.util.IndentingWriter;
60ffe82bdcb5c914b3a60b630c6d3abe6fc9229decBen Gruverimport org.jf.util.SparseIntArray;
6136836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com
62754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruverimport javax.annotation.Nonnull;
63d33fd6773cc3e527b4dbb79245796d556b7facdeBen Gruverimport javax.annotation.Nullable;
646eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.comimport java.io.IOException;
659bc4978139ca38e422ae89065d3062146534132dJesusFreke@JesusFreke.comimport java.util.*;
660b2f7d6a57e90424b3ee455c041aab3996c05f2cJesusFreke@JesusFreke.com
6736836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.compublic class MethodDefinition {
68754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver    @Nonnull public final ClassDefinition classDef;
69754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver    @Nonnull public final Method method;
70754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver    @Nonnull public final MethodImplementation methodImpl;
71d1662b67fecaf835227aff3a136949a2358ccd4eBen Gruver    @Nonnull public final ImmutableList<Instruction> instructions;
72bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver    @Nonnull public final List<Instruction> effectiveInstructions;
73bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver
747fe0543b660587a77f6013905a85e4f737a9a851Ben Gruver    @Nonnull public final ImmutableList<MethodParameter> methodParameters;
75754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver    public RegisterFormatter registerFormatter;
76b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com
77754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver    @Nonnull private final LabelCache labelCache = new LabelCache();
78b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com
79754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver    @Nonnull private final SparseIntArray packedSwitchMap;
80754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver    @Nonnull private final SparseIntArray sparseSwitchMap;
81754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver    @Nonnull private final InstructionOffsetMap instructionOffsetMap;
8210a95181115741071ae23911413a3f731047621cJesusFreke@JesusFreke.com
83754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver    public MethodDefinition(@Nonnull ClassDefinition classDef, @Nonnull Method method,
84754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                            @Nonnull MethodImplementation methodImpl) {
85754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        this.classDef = classDef;
86754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        this.method = method;
87754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        this.methodImpl = methodImpl;
8810a95181115741071ae23911413a3f731047621cJesusFreke@JesusFreke.com
89754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        try {
9010a95181115741071ae23911413a3f731047621cJesusFreke@JesusFreke.com            //TODO: what about try/catch blocks inside the dead code? those will need to be commented out too. ugh.
9110a95181115741071ae23911413a3f731047621cJesusFreke@JesusFreke.com
92d1662b67fecaf835227aff3a136949a2358ccd4eBen Gruver            instructions = ImmutableList.copyOf(methodImpl.getInstructions());
937fe0543b660587a77f6013905a85e4f737a9a851Ben Gruver            methodParameters = ImmutableList.copyOf(method.getParameters());
94754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver
95bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver            effectiveInstructions = Lists.newArrayList(instructions);
96bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver
97754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            packedSwitchMap = new SparseIntArray(0);
98754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            sparseSwitchMap = new SparseIntArray(0);
99d1662b67fecaf835227aff3a136949a2358ccd4eBen Gruver            instructionOffsetMap = new InstructionOffsetMap(instructions);
100754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver
101bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver            int endOffset = instructionOffsetMap.getInstructionCodeOffset(instructions.size()-1) +
102bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver                    instructions.get(instructions.size()-1).getCodeUnits();
103bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver
104754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            for (int i=0; i<instructions.size(); i++) {
105754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                Instruction instruction = instructions.get(i);
106754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver
107754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                Opcode opcode = instruction.getOpcode();
108754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                if (opcode == Opcode.PACKED_SWITCH) {
1094f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver                    boolean valid = true;
110754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                    int codeOffset = instructionOffsetMap.getInstructionCodeOffset(i);
111754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                    int targetOffset = codeOffset + ((OffsetInstruction)instruction).getCodeOffset();
1124f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver                    try {
113bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver                        targetOffset = findPayloadOffset(targetOffset, Opcode.PACKED_SWITCH_PAYLOAD);
1144f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver                    } catch (InvalidSwitchPayload ex) {
1154f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver                        valid = false;
1164f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver                    }
1174f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver                    if (valid) {
118bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver                        if (packedSwitchMap.get(targetOffset, -1) != -1) {
119bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver                            Instruction payloadInstruction =
120bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver                                    findSwitchPayload(targetOffset, Opcode.PACKED_SWITCH_PAYLOAD);
121bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver                            targetOffset = endOffset;
122bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver                            effectiveInstructions.set(i, new ImmutableInstruction31t(opcode,
123bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver                                    ((Instruction31t)instruction).getRegisterA(), targetOffset-codeOffset));
124bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver                            effectiveInstructions.add(payloadInstruction);
125bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver                            endOffset += payloadInstruction.getCodeUnits();
126bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver                        }
1274f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver                        packedSwitchMap.append(targetOffset, codeOffset);
1284f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver                    }
129754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                } else if (opcode == Opcode.SPARSE_SWITCH) {
1304f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver                    boolean valid = true;
131754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                    int codeOffset = instructionOffsetMap.getInstructionCodeOffset(i);
132754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                    int targetOffset = codeOffset + ((OffsetInstruction)instruction).getCodeOffset();
1334f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver                    try {
134bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver                        targetOffset = findPayloadOffset(targetOffset, Opcode.SPARSE_SWITCH_PAYLOAD);
1354f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver                    } catch (InvalidSwitchPayload ex) {
1364f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver                        valid = false;
1374f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver                        // The offset to the payload instruction was invalid. Nothing to do, except that we won't
1384f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver                        // add this instruction to the map.
1394f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver                    }
1404f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver                    if (valid) {
141bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver                        if (sparseSwitchMap.get(targetOffset, -1) != -1) {
142bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver                            Instruction payloadInstruction =
143bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver                                    findSwitchPayload(targetOffset, Opcode.SPARSE_SWITCH_PAYLOAD);
144bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver                            targetOffset = endOffset;
145bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver                            effectiveInstructions.set(i, new ImmutableInstruction31t(opcode,
146bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver                                    ((Instruction31t)instruction).getRegisterA(), targetOffset-codeOffset));
147bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver                            effectiveInstructions.add(payloadInstruction);
148bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver                            endOffset += payloadInstruction.getCodeUnits();
149bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver                        }
1504f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver                        sparseSwitchMap.append(targetOffset, codeOffset);
1514f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver                    }
152b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com                }
153b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com            }
154bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver        } catch (Exception ex) {
1556b93c7cc35141db5c70406b8af609ed0954135f9Ben Gruver            String methodString;
1566b93c7cc35141db5c70406b8af609ed0954135f9Ben Gruver            try {
157f3c33259dd0567294ef814be879b59a450c24f70Izzat Bahadirov                methodString = ReferenceUtil.getMethodDescriptor(method);
1586b93c7cc35141db5c70406b8af609ed0954135f9Ben Gruver            } catch (Exception ex2) {
1596b93c7cc35141db5c70406b8af609ed0954135f9Ben Gruver                throw ExceptionWithContext.withContext(ex, "Error while processing method");
1606b93c7cc35141db5c70406b8af609ed0954135f9Ben Gruver            }
161754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            throw ExceptionWithContext.withContext(ex, "Error while processing method %s", methodString);
162b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com        }
163b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com    }
164b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com
16544c5c07c5724e9448d803b3585c9ef47117c3d4eBen Gruver    public static void writeEmptyMethodTo(IndentingWriter writer, Method method,
1665a5eafb818cc18baeef8bdae1940401da3735f25Ben Gruver                                          BaksmaliOptions options) throws IOException {
1676eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com        writer.write(".method ");
168754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        writeAccessFlags(writer, method.getAccessFlags());
169754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        writer.write(method.getName());
170754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        writer.write("(");
1717fe0543b660587a77f6013905a85e4f737a9a851Ben Gruver        ImmutableList<MethodParameter> methodParameters = ImmutableList.copyOf(method.getParameters());
1727fe0543b660587a77f6013905a85e4f737a9a851Ben Gruver        for (MethodParameter parameter: methodParameters) {
173754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            writer.write(parameter.getType());
174754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        }
175754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        writer.write(")");
176754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        writer.write(method.getReturnType());
1770b2f7d6a57e90424b3ee455c041aab3996c05f2cJesusFreke@JesusFreke.com        writer.write('\n');
17836836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com
1796eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com        writer.indent(4);
18044c5c07c5724e9448d803b3585c9ef47117c3d4eBen Gruver        writeParameters(writer, method, methodParameters, options);
181d33fd6773cc3e527b4dbb79245796d556b7facdeBen Gruver
182d33fd6773cc3e527b4dbb79245796d556b7facdeBen Gruver        String containingClass = null;
1835a5eafb818cc18baeef8bdae1940401da3735f25Ben Gruver        if (options.implicitReferences) {
184d33fd6773cc3e527b4dbb79245796d556b7facdeBen Gruver            containingClass = method.getDefiningClass();
185d33fd6773cc3e527b4dbb79245796d556b7facdeBen Gruver        }
186d33fd6773cc3e527b4dbb79245796d556b7facdeBen Gruver        AnnotationFormatter.writeTo(writer, method.getAnnotations(), containingClass);
187d33fd6773cc3e527b4dbb79245796d556b7facdeBen Gruver
1886eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com        writer.deindent(4);
1890b2f7d6a57e90424b3ee455c041aab3996c05f2cJesusFreke@JesusFreke.com        writer.write(".end method\n");
19036836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com    }
19136836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com
192754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver    public void writeTo(IndentingWriter writer) throws IOException {
193754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        int parameterRegisterCount = 0;
194754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        if (!AccessFlags.STATIC.isSet(method.getAccessFlags())) {
195754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            parameterRegisterCount++;
19636836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com        }
197fa07a1972e3cff56d5615c18a8797ff58fc9f739JesusFreke@JesusFreke.com
198754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        writer.write(".method ");
199754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        writeAccessFlags(writer, method.getAccessFlags());
200754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        writer.write(method.getName());
201754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        writer.write("(");
2027fe0543b660587a77f6013905a85e4f737a9a851Ben Gruver        for (MethodParameter parameter: methodParameters) {
203754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            String type = parameter.getType();
204754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            writer.write(type);
205754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            parameterRegisterCount++;
206754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            if (TypeUtils.isWideType(type)) {
207754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                parameterRegisterCount++;
208754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            }
2093c9013f9c08fa8effc9f6d4dc58212c68eb21742JesusFreke@JesusFreke.com        }
210754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        writer.write(")");
211754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        writer.write(method.getReturnType());
212754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        writer.write('\n');
2133c9013f9c08fa8effc9f6d4dc58212c68eb21742JesusFreke@JesusFreke.com
214754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        writer.indent(4);
2155a5eafb818cc18baeef8bdae1940401da3735f25Ben Gruver        if (classDef.options.localsDirective) {
216754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            writer.write(".locals ");
217754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            writer.printSignedIntAsDec(methodImpl.getRegisterCount() - parameterRegisterCount);
2186eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com        } else {
219754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            writer.write(".registers ");
220754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            writer.printSignedIntAsDec(methodImpl.getRegisterCount());
2216eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com        }
222754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        writer.write('\n');
22344c5c07c5724e9448d803b3585c9ef47117c3d4eBen Gruver        writeParameters(writer, method, methodParameters, classDef.options);
2243c9013f9c08fa8effc9f6d4dc58212c68eb21742JesusFreke@JesusFreke.com
225754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        if (registerFormatter == null) {
22693aa50139c4641d931b05608f73af8879c0de1c2Ben Gruver            registerFormatter = new RegisterFormatter(classDef.options, methodImpl.getRegisterCount(),
22793aa50139c4641d931b05608f73af8879c0de1c2Ben Gruver                    parameterRegisterCount);
2283c9013f9c08fa8effc9f6d4dc58212c68eb21742JesusFreke@JesusFreke.com        }
2293c9013f9c08fa8effc9f6d4dc58212c68eb21742JesusFreke@JesusFreke.com
230d33fd6773cc3e527b4dbb79245796d556b7facdeBen Gruver        String containingClass = null;
2315a5eafb818cc18baeef8bdae1940401da3735f25Ben Gruver        if (classDef.options.implicitReferences) {
232d33fd6773cc3e527b4dbb79245796d556b7facdeBen Gruver            containingClass = method.getDefiningClass();
233d33fd6773cc3e527b4dbb79245796d556b7facdeBen Gruver        }
234d33fd6773cc3e527b4dbb79245796d556b7facdeBen Gruver        AnnotationFormatter.writeTo(writer, method.getAnnotations(), containingClass);
2353c9013f9c08fa8effc9f6d4dc58212c68eb21742JesusFreke@JesusFreke.com
236754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        writer.write('\n');
2376eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com
238db49fd7714893b35ba7de51fae8d8e386f3dc335Ben Gruver        List<MethodItem> methodItems = getMethodItems();
2394b171afedb983fb811990beeec6a15e30a90b455Ben Gruver        for (MethodItem methodItem: methodItems) {
240754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            if (methodItem.writeTo(writer)) {
241754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                writer.write('\n');
2426eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com            }
2436eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com        }
244754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        writer.deindent(4);
245754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        writer.write(".end method\n");
2463c9013f9c08fa8effc9f6d4dc58212c68eb21742JesusFreke@JesusFreke.com    }
2473c9013f9c08fa8effc9f6d4dc58212c68eb21742JesusFreke@JesusFreke.com
248bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver    public Instruction findSwitchPayload(int targetOffset, Opcode type) {
249bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver        int targetIndex;
250bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver        try {
251bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver            targetIndex = instructionOffsetMap.getInstructionIndexAtCodeOffset(targetOffset);
252bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver        } catch (InvalidInstructionOffset ex) {
253bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver            throw new InvalidSwitchPayload(targetOffset);
254bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver        }
255bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver
256bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver        //TODO: does dalvik let you pad with multiple nops?
257bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver        //TODO: does dalvik let a switch instruction point to a non-payload instruction?
258bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver
259bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver        Instruction instruction = instructions.get(targetIndex);
260bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver        if (instruction.getOpcode() != type) {
261bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver            // maybe it's pointing to a NOP padding instruction. Look at the next instruction
262bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver            if (instruction.getOpcode() == Opcode.NOP) {
263bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver                targetIndex += 1;
264bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver                if (targetIndex < instructions.size()) {
265bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver                    instruction = instructions.get(targetIndex);
266bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver                    if (instruction.getOpcode() == type) {
267bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver                        return instruction;
268bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver                    }
269bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver                }
270bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver            }
271bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver            throw new InvalidSwitchPayload(targetOffset);
272bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver        } else {
273bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver            return instruction;
274bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver        }
275bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver    }
276bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver
277bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver    public int findPayloadOffset(int targetOffset, Opcode type) {
2784f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver        int targetIndex;
2794f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver        try {
2804f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver            targetIndex = instructionOffsetMap.getInstructionIndexAtCodeOffset(targetOffset);
2814f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver        } catch (InvalidInstructionOffset ex) {
2824f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver            throw new InvalidSwitchPayload(targetOffset);
2834f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver        }
284754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver
285754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        //TODO: does dalvik let you pad with multiple nops?
286754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        //TODO: does dalvik let a switch instruction point to a non-payload instruction?
287754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver
288754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        Instruction instruction = instructions.get(targetIndex);
289754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        if (instruction.getOpcode() != type) {
290754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            // maybe it's pointing to a NOP padding instruction. Look at the next instruction
291754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            if (instruction.getOpcode() == Opcode.NOP) {
292754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                targetIndex += 1;
293754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                if (targetIndex < instructions.size()) {
294754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                    instruction = instructions.get(targetIndex);
295754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                    if (instruction.getOpcode() == type) {
296754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                        return instructionOffsetMap.getInstructionCodeOffset(targetIndex);
297754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                    }
298754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                }
299754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            }
3004f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver            throw new InvalidSwitchPayload(targetOffset);
301754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        } else {
302754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            return targetOffset;
303c9be5e13034da9827b5598a6257376164745b827JesusFreke@JesusFreke.com        }
304c9be5e13034da9827b5598a6257376164745b827JesusFreke@JesusFreke.com    }
305c9be5e13034da9827b5598a6257376164745b827JesusFreke@JesusFreke.com
306754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver    private static void writeAccessFlags(IndentingWriter writer, int accessFlags)
307754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            throws IOException {
308754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        for (AccessFlags accessFlag: AccessFlags.getAccessFlagsForMethod(accessFlags)) {
309754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            writer.write(accessFlag.toString());
310754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            writer.write(' ');
311b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com        }
312b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com    }
313b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com
3147fe0543b660587a77f6013905a85e4f737a9a851Ben Gruver    private static void writeParameters(IndentingWriter writer, Method method,
31544c5c07c5724e9448d803b3585c9ef47117c3d4eBen Gruver                                        List<? extends MethodParameter> parameters,
3165a5eafb818cc18baeef8bdae1940401da3735f25Ben Gruver                                        BaksmaliOptions options) throws IOException {
317c3a3ee3799e354b6718ce8eee2cf20cbac1ca9d9Ben Gruver        boolean isStatic = AccessFlags.STATIC.isSet(method.getAccessFlags());
318c3a3ee3799e354b6718ce8eee2cf20cbac1ca9d9Ben Gruver        int registerNumber = isStatic?0:1;
3197fe0543b660587a77f6013905a85e4f737a9a851Ben Gruver        for (MethodParameter parameter: parameters) {
320754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            String parameterType = parameter.getType();
321754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            String parameterName = parameter.getName();
322c6e54994a7be1bdbdd751ede7c96e07e7fb1c84fBen Gruver            Collection<? extends Annotation> annotations = parameter.getAnnotations();
3235a5eafb818cc18baeef8bdae1940401da3735f25Ben Gruver            if ((options.debugInfo && parameterName != null) || annotations.size() != 0) {
32416f257ee8f12974c62e50643b2f87533513da455Ben Gruver                writer.write(".param p");
325754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                writer.printSignedIntAsDec(registerNumber);
3263e4e5ec7a4f2bcd82e21ba7caf93c60a981422abBen Gruver
3275a5eafb818cc18baeef8bdae1940401da3735f25Ben Gruver                if (parameterName != null && options.debugInfo) {
32816f257ee8f12974c62e50643b2f87533513da455Ben Gruver                    writer.write(", ");
3293e4e5ec7a4f2bcd82e21ba7caf93c60a981422abBen Gruver                    ReferenceFormatter.writeStringReference(writer, parameterName);
330754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                }
331c3a3ee3799e354b6718ce8eee2cf20cbac1ca9d9Ben Gruver                writer.write("    # ");
33216f257ee8f12974c62e50643b2f87533513da455Ben Gruver                writer.write(parameterType);
333db81d89c2acbd8569f62a941ee2947eb5cd4c5b5Ben Gruver                writer.write("\n");
334754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                if (annotations.size() > 0) {
335754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                    writer.indent(4);
336d33fd6773cc3e527b4dbb79245796d556b7facdeBen Gruver
337d33fd6773cc3e527b4dbb79245796d556b7facdeBen Gruver                    String containingClass = null;
3385a5eafb818cc18baeef8bdae1940401da3735f25Ben Gruver                    if (options.implicitReferences) {
339d33fd6773cc3e527b4dbb79245796d556b7facdeBen Gruver                        containingClass = method.getDefiningClass();
340d33fd6773cc3e527b4dbb79245796d556b7facdeBen Gruver                    }
341d33fd6773cc3e527b4dbb79245796d556b7facdeBen Gruver                    AnnotationFormatter.writeTo(writer, annotations, containingClass);
342754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                    writer.deindent(4);
34316f257ee8f12974c62e50643b2f87533513da455Ben Gruver                    writer.write(".end param\n");
344754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                }
345754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            }
346cb3e0ea38a669633b8daefd538750c8ded46f524Ben Gruver
347754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            registerNumber++;
348754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            if (TypeUtils.isWideType(parameterType)) {
349754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                registerNumber++;
350cb3e0ea38a669633b8daefd538750c8ded46f524Ben Gruver            }
351b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com        }
352b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com    }
353b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com
354754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver    @Nonnull public LabelCache getLabelCache() {
355754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        return labelCache;
356754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver    }
357db26b663aa3b5bb721185b8798b6767710d3c243JesusFreke@JesusFreke.com
358754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver    public int getPackedSwitchBaseAddress(int packedSwitchPayloadCodeOffset) {
359754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        return packedSwitchMap.get(packedSwitchPayloadCodeOffset, -1);
360db26b663aa3b5bb721185b8798b6767710d3c243JesusFreke@JesusFreke.com    }
361db26b663aa3b5bb721185b8798b6767710d3c243JesusFreke@JesusFreke.com
362754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver    public int getSparseSwitchBaseAddress(int sparseSwitchPayloadCodeOffset) {
363754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        return sparseSwitchMap.get(sparseSwitchPayloadCodeOffset, -1);
364343df2f456f38c305ee7d6742f6601d9bde09715Ben Gruver    }
365343df2f456f38c305ee7d6742f6601d9bde09715Ben Gruver
366b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com    private List<MethodItem> getMethodItems() {
367f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com        ArrayList<MethodItem> methodItems = new ArrayList<MethodItem>();
3689bc4978139ca38e422ae89065d3062146534132dJesusFreke@JesusFreke.com
369827e2db34dc3b8b5504c148a09d594b5c0ddbd64Ben Gruver        if ((classDef.options.registerInfo != 0) || (classDef.options.normalizeVirtualMethods) ||
370827e2db34dc3b8b5504c148a09d594b5c0ddbd64Ben Gruver                (classDef.options.deodex && needsAnalyzed())) {
371c91b03ba45ccacfa7b0ad52592a42e8fd8c18da1Ben Gruver            addAnalyzedInstructionMethodItems(methodItems);
372c91b03ba45ccacfa7b0ad52592a42e8fd8c18da1Ben Gruver        } else {
373c91b03ba45ccacfa7b0ad52592a42e8fd8c18da1Ben Gruver            addInstructionMethodItems(methodItems);
374c91b03ba45ccacfa7b0ad52592a42e8fd8c18da1Ben Gruver        }
375f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
376f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com        addTries(methodItems);
3775a5eafb818cc18baeef8bdae1940401da3735f25Ben Gruver        if (classDef.options.debugInfo) {
3788913c59363230bc1bf787b7e24941cb13209de0cJesusFreke@JesusFreke.com            addDebugInfo(methodItems);
3798913c59363230bc1bf787b7e24941cb13209de0cJesusFreke@JesusFreke.com        }
380f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
3815a5eafb818cc18baeef8bdae1940401da3735f25Ben Gruver        if (classDef.options.sequentialLabels) {
382f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com            setLabelSequentialNumbers();
383f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com        }
384f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
385f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com        for (LabelMethodItem labelMethodItem: labelCache.getLabels()) {
386e01409c11f10de58a47df9bc02c6c715b75c6289JesusFreke@JesusFreke.com            methodItems.add(labelMethodItem);
387f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com        }
388f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
389f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com        Collections.sort(methodItems);
390f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
391f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com        return methodItems;
392f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com    }
393f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
394c91b03ba45ccacfa7b0ad52592a42e8fd8c18da1Ben Gruver    private boolean needsAnalyzed() {
395c91b03ba45ccacfa7b0ad52592a42e8fd8c18da1Ben Gruver        for (Instruction instruction: methodImpl.getInstructions()) {
396c91b03ba45ccacfa7b0ad52592a42e8fd8c18da1Ben Gruver            if (instruction.getOpcode().odexOnly()) {
397c91b03ba45ccacfa7b0ad52592a42e8fd8c18da1Ben Gruver                return true;
398c91b03ba45ccacfa7b0ad52592a42e8fd8c18da1Ben Gruver            }
399c91b03ba45ccacfa7b0ad52592a42e8fd8c18da1Ben Gruver        }
400c91b03ba45ccacfa7b0ad52592a42e8fd8c18da1Ben Gruver        return false;
401c91b03ba45ccacfa7b0ad52592a42e8fd8c18da1Ben Gruver    }
402c91b03ba45ccacfa7b0ad52592a42e8fd8c18da1Ben Gruver
403f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com    private void addInstructionMethodItems(List<MethodItem> methodItems) {
404f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com        int currentCodeAddress = 0;
405bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver
406bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver        for (int i=0; i<effectiveInstructions.size(); i++) {
407bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver            Instruction instruction = effectiveInstructions.get(i);
408f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
409f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com            MethodItem methodItem = InstructionMethodItemFactory.makeInstructionFormatMethodItem(this,
410754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                    currentCodeAddress, instruction);
411f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
412f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com            methodItems.add(methodItem);
413f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
414bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver            if (i != effectiveInstructions.size() - 1) {
415f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com                methodItems.add(new BlankMethodItem(currentCodeAddress));
416f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com            }
417f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
4185a5eafb818cc18baeef8bdae1940401da3735f25Ben Gruver            if (classDef.options.codeOffsets) {
419f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com                methodItems.add(new MethodItem(currentCodeAddress) {
420f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
421f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com                    @Override
422f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com                    public double getSortOrder() {
423f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com                        return -1000;
424f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com                    }
425f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
426f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com                    @Override
427f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com                    public boolean writeTo(IndentingWriter writer) throws IOException {
428f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com                        writer.write("#@");
429754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                        writer.printUnsignedLongAsHex(codeAddress & 0xFFFFFFFFL);
430f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com                        return true;
431f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com                    }
432f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com                });
433f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com            }
434c9be5e13034da9827b5598a6257376164745b827JesusFreke@JesusFreke.com
435961c21be988e842cb552e8e55f59b69656bffc6cBen Gruver            if (classDef.options.accessorComments && classDef.options.syntheticAccessorResolver != null &&
436961c21be988e842cb552e8e55f59b69656bffc6cBen Gruver                    (instruction instanceof ReferenceInstruction)) {
437754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                Opcode opcode = instruction.getOpcode();
4382f376953b4c96542f200724727e4dac74dd27425jesusfreke@jesusfreke.com
4392b8845bb247e3e5ee154966866b53fa9887e2609Ben Gruver                if (opcode.referenceType == ReferenceType.METHOD) {
4404f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver                    MethodReference methodReference = null;
4414f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver                    try {
4424f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver                        methodReference = (MethodReference)((ReferenceInstruction)instruction).getReference();
4434f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver                    } catch (InvalidItemIndex ex) {
4444f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver                        // just ignore it for now. We'll deal with it later, when processing the instructions
4454f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver                        // themselves
4464f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver                    }
4472b8845bb247e3e5ee154966866b53fa9887e2609Ben Gruver
4484f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver                    if (methodReference != null &&
4494f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver                            SyntheticAccessorResolver.looksLikeSyntheticAccessor(methodReference.getName())) {
450bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver                        AccessedMember accessedMember =
45193aa50139c4641d931b05608f73af8879c0de1c2Ben Gruver                                classDef.options.syntheticAccessorResolver.getAccessedMember(methodReference);
4522f376953b4c96542f200724727e4dac74dd27425jesusfreke@jesusfreke.com                        if (accessedMember != null) {
4532f376953b4c96542f200724727e4dac74dd27425jesusfreke@jesusfreke.com                            methodItems.add(new SyntheticAccessCommentMethodItem(accessedMember, currentCodeAddress));
4542f376953b4c96542f200724727e4dac74dd27425jesusfreke@jesusfreke.com                        }
4552f376953b4c96542f200724727e4dac74dd27425jesusfreke@jesusfreke.com                    }
4562f376953b4c96542f200724727e4dac74dd27425jesusfreke@jesusfreke.com                }
4572b8845bb247e3e5ee154966866b53fa9887e2609Ben Gruver            }
4582f376953b4c96542f200724727e4dac74dd27425jesusfreke@jesusfreke.com
459754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            currentCodeAddress += instruction.getCodeUnits();
460f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com        }
461f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com    }
462f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
463c91b03ba45ccacfa7b0ad52592a42e8fd8c18da1Ben Gruver    private void addAnalyzedInstructionMethodItems(List<MethodItem> methodItems) {
46493aa50139c4641d931b05608f73af8879c0de1c2Ben Gruver        MethodAnalyzer methodAnalyzer = new MethodAnalyzer(classDef.options.classPath, method,
465827e2db34dc3b8b5504c148a09d594b5c0ddbd64Ben Gruver                classDef.options.inlineResolver, classDef.options.normalizeVirtualMethods);
466f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
467c91b03ba45ccacfa7b0ad52592a42e8fd8c18da1Ben Gruver        AnalysisException analysisException = methodAnalyzer.getAnalysisException();
468c91b03ba45ccacfa7b0ad52592a42e8fd8c18da1Ben Gruver        if (analysisException != null) {
469a55990c876eab2489e824711da23e5abc7bff1a5Ben Gruver            // TODO: need to keep track of whether any errors occurred, so we can exit with a non-zero result
470f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com            methodItems.add(new CommentMethodItem(
471a55990c876eab2489e824711da23e5abc7bff1a5Ben Gruver                    String.format("AnalysisException: %s", analysisException.getMessage()),
472c91b03ba45ccacfa7b0ad52592a42e8fd8c18da1Ben Gruver                    analysisException.codeAddress, Integer.MIN_VALUE));
473a55990c876eab2489e824711da23e5abc7bff1a5Ben Gruver            analysisException.printStackTrace(System.err);
4747e24a9f010eeeff54f7ca0cb589a75cc251fabddJesusFreke@JesusFreke.com        }
475f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
476c91b03ba45ccacfa7b0ad52592a42e8fd8c18da1Ben Gruver        List<AnalyzedInstruction> instructions = methodAnalyzer.getAnalyzedInstructions();
477ad1085e32a17b342c2418c117c59d9c8305d71fcJesusFreke@JesusFreke.com
478b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com        int currentCodeAddress = 0;
479ef24b31c9872b24f60c88bdae9b2d8c93eb36feeJesusFreke@JesusFreke.com        for (int i=0; i<instructions.size(); i++) {
480ef24b31c9872b24f60c88bdae9b2d8c93eb36feeJesusFreke@JesusFreke.com            AnalyzedInstruction instruction = instructions.get(i);
481ad1085e32a17b342c2418c117c59d9c8305d71fcJesusFreke@JesusFreke.com
482c91b03ba45ccacfa7b0ad52592a42e8fd8c18da1Ben Gruver            MethodItem methodItem = InstructionMethodItemFactory.makeInstructionFormatMethodItem(
483c91b03ba45ccacfa7b0ad52592a42e8fd8c18da1Ben Gruver                    this, currentCodeAddress, instruction.getInstruction());
484650725bbd3c5e10b9f29d3bcbab473b20a89d57bJesusFreke@JesusFreke.com
485e01409c11f10de58a47df9bc02c6c715b75c6289JesusFreke@JesusFreke.com            methodItems.add(methodItem);
4860c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
487c91b03ba45ccacfa7b0ad52592a42e8fd8c18da1Ben Gruver            if (instruction.getInstruction().getOpcode().format == Format.UnresolvedOdexInstruction) {
4886eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com                methodItems.add(new CommentedOutMethodItem(
489c91b03ba45ccacfa7b0ad52592a42e8fd8c18da1Ben Gruver                        InstructionMethodItemFactory.makeInstructionFormatMethodItem(
490c91b03ba45ccacfa7b0ad52592a42e8fd8c18da1Ben Gruver                                this, currentCodeAddress, instruction.getOriginalInstruction())));
4910c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            }
4927ab77bc90be62b0688c97d4476e3bd219eace0daJesusFreke@JesusFreke.com
493ef24b31c9872b24f60c88bdae9b2d8c93eb36feeJesusFreke@JesusFreke.com            if (i != instructions.size() - 1) {
4946eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com                methodItems.add(new BlankMethodItem(currentCodeAddress));
495b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com            }
496e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com
4975a5eafb818cc18baeef8bdae1940401da3735f25Ben Gruver            if (classDef.options.codeOffsets) {
4986eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com                methodItems.add(new MethodItem(currentCodeAddress) {
4992bdbf739bfd935877e463bc36df0e446b1dfb09fJesusFreke@JesusFreke.com
5006eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com                    @Override
5016eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com                    public double getSortOrder() {
5026eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com                        return -1000;
5031c56c7e7507dc24ae1ed2f693c793d94df814c76JesusFreke@JesusFreke.com                    }
5041c56c7e7507dc24ae1ed2f693c793d94df814c76JesusFreke@JesusFreke.com
5056eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com                    @Override
5060b2f7d6a57e90424b3ee455c041aab3996c05f2cJesusFreke@JesusFreke.com                    public boolean writeTo(IndentingWriter writer) throws IOException {
5076eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com                        writer.write("#@");
508c91b03ba45ccacfa7b0ad52592a42e8fd8c18da1Ben Gruver                        writer.printUnsignedLongAsHex(codeAddress & 0xFFFFFFFFL);
5096eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com                        return true;
5101c56c7e7507dc24ae1ed2f693c793d94df814c76JesusFreke@JesusFreke.com                    }
5116eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com                });
5126eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com            }
5131c56c7e7507dc24ae1ed2f693c793d94df814c76JesusFreke@JesusFreke.com
51493aa50139c4641d931b05608f73af8879c0de1c2Ben Gruver            if (classDef.options.registerInfo != 0 &&
51593aa50139c4641d931b05608f73af8879c0de1c2Ben Gruver                    !instruction.getInstruction().getOpcode().format.isPayloadFormat) {
5166eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com                methodItems.add(
51793aa50139c4641d931b05608f73af8879c0de1c2Ben Gruver                        new PreInstructionRegisterInfoMethodItem(classDef.options.registerInfo,
518c91b03ba45ccacfa7b0ad52592a42e8fd8c18da1Ben Gruver                                methodAnalyzer, registerFormatter, instruction, currentCodeAddress));
5191c56c7e7507dc24ae1ed2f693c793d94df814c76JesusFreke@JesusFreke.com
5206eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com                methodItems.add(
521c91b03ba45ccacfa7b0ad52592a42e8fd8c18da1Ben Gruver                        new PostInstructionRegisterInfoMethodItem(registerFormatter, instruction, currentCodeAddress));
5221c56c7e7507dc24ae1ed2f693c793d94df814c76JesusFreke@JesusFreke.com            }
5237e24a9f010eeeff54f7ca0cb589a75cc251fabddJesusFreke@JesusFreke.com
524c91b03ba45ccacfa7b0ad52592a42e8fd8c18da1Ben Gruver            currentCodeAddress += instruction.getInstruction().getCodeUnits();
525b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com        }
526c91b03ba45ccacfa7b0ad52592a42e8fd8c18da1Ben Gruver    }
527e24e70f9ad584d45d2a2af911c1d056163f1bc74JesusFreke@JesusFreke.com
528b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com    private void addTries(List<MethodItem> methodItems) {
5291bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver        List<? extends TryBlock<? extends ExceptionHandler>> tryBlocks = methodImpl.getTryBlocks();
530754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        if (tryBlocks.size() == 0) {
531b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com            return;
532b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com        }
533e24e70f9ad584d45d2a2af911c1d056163f1bc74JesusFreke@JesusFreke.com
534754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        int lastInstructionAddress = instructionOffsetMap.getInstructionCodeOffset(instructions.size() - 1);
535754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        int codeSize = lastInstructionAddress + instructions.get(instructions.size() - 1).getCodeUnits();
536b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com
5371bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver        for (TryBlock<? extends ExceptionHandler> tryBlock: tryBlocks) {
538bea9627ed75546d7df9e79c927b9329c70a29808Ben Gruver            int startAddress = tryBlock.getStartCodeAddress();
539754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            int endAddress = startAddress + tryBlock.getCodeUnitCount();
540b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com
5415934004fe3c1e9617793aa120e88f5df1b651c14Ben Gruver            if (startAddress >= codeSize) {
5425934004fe3c1e9617793aa120e88f5df1b651c14Ben Gruver                throw new RuntimeException(String.format("Try start offset %d is past the end of the code block.",
5435934004fe3c1e9617793aa120e88f5df1b651c14Ben Gruver                        startAddress));
5445934004fe3c1e9617793aa120e88f5df1b651c14Ben Gruver            }
5455934004fe3c1e9617793aa120e88f5df1b651c14Ben Gruver            // Note: not >=. endAddress == codeSize is valid, when the try covers the last instruction
5465934004fe3c1e9617793aa120e88f5df1b651c14Ben Gruver            if (endAddress > codeSize) {
5475934004fe3c1e9617793aa120e88f5df1b651c14Ben Gruver                throw new RuntimeException(String.format("Try end offset %d is past the end of the code block.",
5485934004fe3c1e9617793aa120e88f5df1b651c14Ben Gruver                        endAddress));
5495934004fe3c1e9617793aa120e88f5df1b651c14Ben Gruver            }
5505934004fe3c1e9617793aa120e88f5df1b651c14Ben Gruver
551b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com            /**
552b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com             * The end address points to the address immediately after the end of the last
553b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com             * instruction that the try block covers. We want the .catch directive and end_try
554b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com             * label to be associated with the last covered instruction, so we need to get
555b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com             * the address for that instruction
556b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com             */
557b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com
558754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            int lastCoveredIndex = instructionOffsetMap.getInstructionIndexAtCodeOffset(endAddress - 1, false);
559754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            int lastCoveredAddress = instructionOffsetMap.getInstructionCodeOffset(lastCoveredIndex);
560ad1085e32a17b342c2418c117c59d9c8305d71fcJesusFreke@JesusFreke.com
561754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            for (ExceptionHandler handler: tryBlock.getExceptionHandlers()) {
562bea9627ed75546d7df9e79c927b9329c70a29808Ben Gruver                int handlerAddress = handler.getHandlerCodeAddress();
563bea9627ed75546d7df9e79c927b9329c70a29808Ben Gruver                if (handlerAddress >= codeSize) {
564754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                    throw new ExceptionWithContext(
565bea9627ed75546d7df9e79c927b9329c70a29808Ben Gruver                            "Exception handler offset %d is past the end of the code block.", handlerAddress);
5665934004fe3c1e9617793aa120e88f5df1b651c14Ben Gruver                }
5675934004fe3c1e9617793aa120e88f5df1b651c14Ben Gruver
568b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com                //use the address from the last covered instruction
56993aa50139c4641d931b05608f73af8879c0de1c2Ben Gruver                CatchMethodItem catchMethodItem = new CatchMethodItem(classDef.options, labelCache, lastCoveredAddress,
570bea9627ed75546d7df9e79c927b9329c70a29808Ben Gruver                        handler.getExceptionType(), startAddress, endAddress, handlerAddress);
571b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com                methodItems.add(catchMethodItem);
572c65a8d8b5f2091a6bd835617262840a3f52c5c00JesusFreke@JesusFreke.com            }
573c65a8d8b5f2091a6bd835617262840a3f52c5c00JesusFreke@JesusFreke.com        }
574b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com    }
575c65a8d8b5f2091a6bd835617262840a3f52c5c00JesusFreke@JesusFreke.com
576b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com    private void addDebugInfo(final List<MethodItem> methodItems) {
577754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        for (DebugItem debugItem: methodImpl.getDebugItems()) {
578754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            methodItems.add(DebugMethodItem.build(registerFormatter, debugItem));
579c65a8d8b5f2091a6bd835617262840a3f52c5c00JesusFreke@JesusFreke.com        }
580b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com    }
581e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com
582b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com    private void setLabelSequentialNumbers() {
583b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com        HashMap<String, Integer> nextLabelSequenceByType = new HashMap<String, Integer>();
584b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com        ArrayList<LabelMethodItem> sortedLabels = new ArrayList<LabelMethodItem>(labelCache.getLabels());
585e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com
586b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com        //sort the labels by their location in the method
587b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com        Collections.sort(sortedLabels);
588e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com
589b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com        for (LabelMethodItem labelMethodItem: sortedLabels) {
590b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com            Integer labelSequence = nextLabelSequenceByType.get(labelMethodItem.getLabelPrefix());
591b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com            if (labelSequence == null) {
592b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com                labelSequence = 0;
593e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com            }
594b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com            labelMethodItem.setLabelSequence(labelSequence);
595b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com            nextLabelSequenceByType.put(labelMethodItem.getLabelPrefix(), labelSequence + 1);
596e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com        }
597e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com    }
598e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com
599d33fd6773cc3e527b4dbb79245796d556b7facdeBen Gruver    @Nullable
600d33fd6773cc3e527b4dbb79245796d556b7facdeBen Gruver    private String getContainingClassForImplicitReference() {
6015a5eafb818cc18baeef8bdae1940401da3735f25Ben Gruver        if (classDef.options.implicitReferences) {
602d33fd6773cc3e527b4dbb79245796d556b7facdeBen Gruver            return classDef.classDef.getType();
603d33fd6773cc3e527b4dbb79245796d556b7facdeBen Gruver        }
604d33fd6773cc3e527b4dbb79245796d556b7facdeBen Gruver        return null;
605d33fd6773cc3e527b4dbb79245796d556b7facdeBen Gruver    }
606d33fd6773cc3e527b4dbb79245796d556b7facdeBen Gruver
607e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com    public static class LabelCache {
608e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com        protected HashMap<LabelMethodItem, LabelMethodItem> labels = new HashMap<LabelMethodItem, LabelMethodItem>();
609e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com
610e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com        public LabelCache() {
611e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com        }
612e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com
613e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com        public LabelMethodItem internLabel(LabelMethodItem labelMethodItem) {
614e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com            LabelMethodItem internedLabelMethodItem = labels.get(labelMethodItem);
615e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com            if (internedLabelMethodItem != null) {
616e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com                return internedLabelMethodItem;
617e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com            }
618e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com            labels.put(labelMethodItem, labelMethodItem);
619e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com            return labelMethodItem;
620e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com        }
621e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com
622e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com
623e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com        public Collection<LabelMethodItem> getLabels() {
624e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com            return labels.values();
625e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com        }
62636836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com    }
6274f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver
6284f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver    public static class InvalidSwitchPayload extends ExceptionWithContext {
6294f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver        private final int payloadOffset;
6304f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver
6314f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver        public InvalidSwitchPayload(int payloadOffset) {
6324f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver            super("No switch payload at offset: %d", payloadOffset);
6334f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver            this.payloadOffset = payloadOffset;
6344f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver        }
6354f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver
6364f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver        public int getPayloadOffset() {
6374f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver            return payloadOffset;
6384f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver        }
6394f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver    }
64036836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com}
641