DexBackedMethodImplementation.java revision 65d969c23b5ef14f8a51c88fdb7c5d5319a1b555
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.util.DebugInfo;
37import org.jf.dexlib2.dexbacked.util.FixedSizeList;
38import org.jf.dexlib2.dexbacked.util.VariableSizeLookaheadIterator;
39import org.jf.dexlib2.iface.MethodImplementation;
40import org.jf.dexlib2.iface.MethodParameter;
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 java.util.Iterator;
48import java.util.List;
49
50public class DexBackedMethodImplementation implements MethodImplementation {
51    @Nonnull public final DexBuffer dexBuf;
52    @Nonnull public final DexBackedMethod method;
53    private final int codeOffset;
54
55    // code_item offsets
56    private static final int TRIES_SIZE_OFFSET = 6;
57    private static final int DEBUG_OFFSET_OFFSET = 8;
58    private static final int INSTRUCTIONS_SIZE_OFFSET = 12;
59    private static final int INSTRUCTIONS_START_OFFSET = 16;
60
61    private static final int TRY_ITEM_SIZE = 8;
62
63    public DexBackedMethodImplementation(@Nonnull DexBuffer dexBuf,
64                                         @Nonnull DexBackedMethod method,
65                                         int codeOffset) {
66        this.dexBuf = dexBuf;
67        this.method = method;
68        this.codeOffset = codeOffset;
69    }
70
71    @Override public int getRegisterCount() { return dexBuf.readUshort(codeOffset); }
72
73    @Nonnull @Override public Iterable<? extends Instruction> getInstructions() {
74        // instructionsSize is the number of 16-bit code units in the instruction list, not the number of instructions
75        int instructionsSize = dexBuf.readSmallUint(codeOffset + INSTRUCTIONS_SIZE_OFFSET);
76
77        final int instructionsStartOffset = codeOffset + INSTRUCTIONS_START_OFFSET;
78        final int endOffset = instructionsStartOffset + (instructionsSize*2);
79        return new Iterable<Instruction>() {
80            @Override
81            public Iterator<Instruction> iterator() {
82                return new VariableSizeLookaheadIterator<Instruction>(dexBuf, instructionsStartOffset) {
83                    @Override
84                    protected Instruction readNextItem(@Nonnull DexReader reader) {
85                        if (reader.getOffset() >= endOffset) {
86                            return null;
87                        }
88                        return DexBackedInstruction.readFrom(reader);
89                    }
90                };
91            }
92        };
93    }
94
95    @Nonnull
96    @Override
97    public List<? extends TryBlock> getTryBlocks() {
98        final int triesSize = dexBuf.readUshort(codeOffset + TRIES_SIZE_OFFSET);
99        if (triesSize > 0) {
100            int instructionsSize = dexBuf.readSmallUint(codeOffset + INSTRUCTIONS_SIZE_OFFSET);
101            final int triesStartOffset = AlignmentUtils.alignOffset(
102                    codeOffset + INSTRUCTIONS_START_OFFSET + (instructionsSize*2), 4);
103            final int handlersStartOffset = triesStartOffset + triesSize*TRY_ITEM_SIZE;
104
105            return new FixedSizeList<TryBlock>() {
106                @Nonnull
107                @Override
108                public TryBlock readItem(int index) {
109                    return new DexBackedTryBlock(dexBuf,
110                            triesStartOffset + index*TRY_ITEM_SIZE,
111                            handlersStartOffset);
112                }
113
114                @Override
115                public int size() {
116                    return triesSize;
117                }
118            };
119        }
120        return ImmutableList.of();
121    }
122
123    @Nonnull
124    private DebugInfo getDebugInfo() {
125        return DebugInfo.newOrEmpty(dexBuf, dexBuf.readSmallUint(codeOffset + DEBUG_OFFSET_OFFSET), this);
126    }
127
128    @Nonnull @Override
129    public Iterable<? extends DebugItem> getDebugItems() {
130        return getDebugInfo();
131    }
132
133    @Nonnull
134    public List<? extends MethodParameter> getParametersWithNames() {
135        return getDebugInfo().getParametersWithNames();
136    }
137}
138