DexBackedMethodImplementation.java revision e8158c86efe5494fb5b369e096c7a857623a1b11
1/*
2 * Copyright 2012, Google Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 *     * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *     * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
15 *     * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32package org.jf.dexlib2.dexbacked;
33
34import com.google.common.collect.ImmutableList;
35import org.jf.dexlib2.dexbacked.instruction.DexBackedInstruction;
36import org.jf.dexlib2.dexbacked.raw.CodeItem;
37import org.jf.dexlib2.dexbacked.util.DebugInfo;
38import org.jf.dexlib2.dexbacked.util.FixedSizeList;
39import org.jf.dexlib2.dexbacked.util.VariableSizeLookaheadIterator;
40import org.jf.dexlib2.iface.MethodImplementation;
41import org.jf.dexlib2.iface.TryBlock;
42import org.jf.dexlib2.iface.debug.DebugItem;
43import org.jf.dexlib2.iface.instruction.Instruction;
44import org.jf.util.AlignmentUtils;
45
46import javax.annotation.Nonnull;
47import javax.annotation.Nullable;
48import java.util.Iterator;
49import java.util.List;
50
51public class DexBackedMethodImplementation implements MethodImplementation {
52    @Nonnull public final DexBackedDexFile dexFile;
53    @Nonnull public final DexBackedMethod method;
54    private final int codeOffset;
55
56    public DexBackedMethodImplementation(@Nonnull DexBackedDexFile dexFile,
57                                         @Nonnull DexBackedMethod method,
58                                         int codeOffset) {
59        this.dexFile = dexFile;
60        this.method = method;
61        this.codeOffset = codeOffset;
62    }
63
64    @Override public int getRegisterCount() { return dexFile.readUshort(codeOffset); }
65
66    @Nonnull @Override public Iterable<? extends Instruction> getInstructions() {
67        // instructionsSize is the number of 16-bit code units in the instruction list, not the number of instructions
68        int instructionsSize = dexFile.readSmallUint(codeOffset + CodeItem.INSTRUCTION_COUNT_OFFSET);
69
70        final int instructionsStartOffset = codeOffset + CodeItem.INSTRUCTION_START_OFFSET;
71        final int endOffset = instructionsStartOffset + (instructionsSize*2);
72        return new Iterable<Instruction>() {
73            @Override
74            public Iterator<Instruction> iterator() {
75                return new VariableSizeLookaheadIterator<Instruction>(dexFile, instructionsStartOffset) {
76                    @Override
77                    protected Instruction readNextItem(@Nonnull DexReader reader) {
78                        if (reader.getOffset() >= endOffset) {
79                            return null;
80                        }
81                        return DexBackedInstruction.readFrom(reader);
82                    }
83                };
84            }
85        };
86    }
87
88    @Nonnull
89    @Override
90    public List<? extends TryBlock> getTryBlocks() {
91        // TODO: provide utility to put try blocks into a "canonical", easy to use format, which more closely matches java's try blocks
92        final int triesSize = dexFile.readUshort(codeOffset + CodeItem.TRIES_SIZE_OFFSET);
93        if (triesSize > 0) {
94            int instructionsSize = dexFile.readSmallUint(codeOffset + CodeItem.INSTRUCTION_COUNT_OFFSET);
95            final int triesStartOffset = AlignmentUtils.alignOffset(
96                    codeOffset + CodeItem.INSTRUCTION_START_OFFSET + (instructionsSize*2), 4);
97            final int handlersStartOffset = triesStartOffset + triesSize*CodeItem.TryItem.ITEM_SIZE;
98
99            return new FixedSizeList<TryBlock>() {
100                @Nonnull
101                @Override
102                public TryBlock readItem(int index) {
103                    return new DexBackedTryBlock(dexFile,
104                            triesStartOffset + index*CodeItem.TryItem.ITEM_SIZE,
105                            handlersStartOffset);
106                }
107
108                @Override
109                public int size() {
110                    return triesSize;
111                }
112            };
113        }
114        return ImmutableList.of();
115    }
116
117    @Nonnull
118    private DebugInfo getDebugInfo() {
119        return DebugInfo.newOrEmpty(dexFile, dexFile.readSmallUint(codeOffset + CodeItem.DEBUG_INFO_OFFSET), this);
120    }
121
122    @Nonnull @Override
123    public Iterable<? extends DebugItem> getDebugItems() {
124        return getDebugInfo();
125    }
126
127    @Nonnull
128    public Iterator<String> getParameterNames(@Nullable DexReader dexReader) {
129        return getDebugInfo().getParameterNames(dexReader);
130    }
131}
132