ConcreteMethod.java revision de75089fb7216d19e9c22cce4dc62a49513477d3
1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.dx.cf.code;
18
19import com.android.dx.cf.attrib.AttCode;
20import com.android.dx.cf.attrib.AttLineNumberTable;
21import com.android.dx.cf.attrib.AttLocalVariableTable;
22import com.android.dx.cf.attrib.AttLocalVariableTypeTable;
23import com.android.dx.cf.attrib.AttSourceFile;
24import com.android.dx.cf.iface.AttributeList;
25import com.android.dx.cf.iface.ClassFile;
26import com.android.dx.cf.iface.Method;
27import com.android.dx.rop.code.AccessFlags;
28import com.android.dx.rop.code.SourcePosition;
29import com.android.dx.rop.cst.CstNat;
30import com.android.dx.rop.cst.CstType;
31import com.android.dx.rop.cst.CstUtf8;
32import com.android.dx.rop.type.Prototype;
33
34/**
35 * Container for all the giblets that make up a concrete Java bytecode method.
36 * It implements {@link Method}, so it provides all the original access
37 * (by delegation), but it also constructs and keeps useful versions of
38 * stuff extracted from the method's {@code Code} attribute.
39 */
40public final class ConcreteMethod implements Method {
41    /** {@code non-null;} method being wrapped */
42    private final Method method;
43
44    /**
45     * {@code null-ok;} the class's {@code SourceFile} attribute value,
46     * if any
47     */
48    private final CstUtf8 sourceFile;
49
50    /**
51     * whether the class that this method is part of is defined with
52     * {@code ACC_SUPER}
53     */
54    private final boolean accSuper;
55
56    /** {@code non-null;} the code attribute */
57    private final AttCode attCode;
58
59    /** {@code non-null;} line number list */
60    private final LineNumberList lineNumbers;
61
62    /** {@code non-null;} local variable list */
63    private final LocalVariableList localVariables;
64
65    /**
66     * Constructs an instance.
67     *
68     * @param method {@code non-null;} the method to be based on
69     * @param cf {@code non-null;} the class file that contains this method
70     * @param keepLines whether to keep the line number information
71     * (if any)
72     * @param keepLocals whether to keep the local variable
73     * information (if any)
74     */
75    public ConcreteMethod(Method method, ClassFile cf, boolean keepLines,
76                          boolean keepLocals) {
77        this.method = method;
78        this.accSuper = (cf.getAccessFlags() & AccessFlags.ACC_SUPER) != 0;
79        this.sourceFile = cf.getSourceFile();
80
81        AttributeList attribs = method.getAttributes();
82        this.attCode = (AttCode) attribs.findFirst(AttCode.ATTRIBUTE_NAME);
83
84        AttributeList codeAttribs = attCode.getAttributes();
85
86        /*
87         * Combine all LineNumberTable attributes into one, with the
88         * combined result saved into the instance. The following code
89         * isn't particularly efficient for doing merges, but as far
90         * as I know, this situation rarely occurs "in the
91         * wild," so there's not much point in optimizing for it.
92         */
93        LineNumberList lineNumbers = LineNumberList.EMPTY;
94        if (keepLines) {
95            for (AttLineNumberTable lnt = (AttLineNumberTable)
96                     codeAttribs.findFirst(AttLineNumberTable.ATTRIBUTE_NAME);
97                 lnt != null;
98                 lnt = (AttLineNumberTable) codeAttribs.findNext(lnt)) {
99                lineNumbers = LineNumberList.concat(lineNumbers,
100                        lnt.getLineNumbers());
101            }
102        }
103        this.lineNumbers = lineNumbers;
104
105        LocalVariableList localVariables = LocalVariableList.EMPTY;
106        if (keepLocals) {
107            /*
108             * Do likewise (and with the same caveat) for
109             * LocalVariableTable and LocalVariableTypeTable attributes.
110             * This combines both of these kinds of attribute into a
111             * single LocalVariableList.
112             */
113            for (AttLocalVariableTable lvt = (AttLocalVariableTable)
114                     codeAttribs.findFirst(
115                             AttLocalVariableTable.ATTRIBUTE_NAME);
116                 lvt != null;
117                 lvt = (AttLocalVariableTable) codeAttribs.findNext(lvt)) {
118                localVariables =
119                    LocalVariableList.concat(localVariables,
120                            lvt.getLocalVariables());
121            }
122
123            LocalVariableList typeList = LocalVariableList.EMPTY;
124            for (AttLocalVariableTypeTable lvtt = (AttLocalVariableTypeTable)
125                     codeAttribs.findFirst(
126                             AttLocalVariableTypeTable.ATTRIBUTE_NAME);
127                 lvtt != null;
128                 lvtt =
129                     (AttLocalVariableTypeTable) codeAttribs.findNext(lvtt)) {
130                typeList =
131                    LocalVariableList.concat(typeList,
132                            lvtt.getLocalVariables());
133            }
134
135            if (typeList.size() != 0) {
136                localVariables =
137                    LocalVariableList.mergeDescriptorsAndSignatures(
138                            localVariables, typeList);
139            }
140        }
141        this.localVariables = localVariables;
142    }
143
144    /** {@inheritDoc} */
145    public CstNat getNat() {
146        return method.getNat();
147    }
148
149    /** {@inheritDoc} */
150    public CstUtf8 getName() {
151        return method.getName();
152    }
153
154    /** {@inheritDoc} */
155    public CstUtf8 getDescriptor() {
156        return method.getDescriptor();
157    }
158
159    /** {@inheritDoc} */
160    public int getAccessFlags() {
161        return method.getAccessFlags();
162    }
163
164    /** {@inheritDoc} */
165    public AttributeList getAttributes() {
166        return method.getAttributes();
167    }
168
169    /** {@inheritDoc} */
170    public CstType getDefiningClass() {
171        return method.getDefiningClass();
172    }
173
174    /** {@inheritDoc} */
175    public Prototype getEffectiveDescriptor() {
176        return method.getEffectiveDescriptor();
177    }
178
179    /**
180     * Gets whether the class that this method is part of is defined with
181     * {@code ACC_SUPER}.
182     *
183     * @return the {@code ACC_SUPER} value
184     */
185    public boolean getAccSuper() {
186        return accSuper;
187    }
188
189    /**
190     * Gets the maximum stack size.
191     *
192     * @return {@code >= 0;} the maximum stack size
193     */
194    public int getMaxStack() {
195        return attCode.getMaxStack();
196    }
197
198    /**
199     * Gets the number of locals.
200     *
201     * @return {@code >= 0;} the number of locals
202     */
203    public int getMaxLocals() {
204        return attCode.getMaxLocals();
205    }
206
207    /**
208     * Gets the bytecode array.
209     *
210     * @return {@code non-null;} the bytecode array
211     */
212    public BytecodeArray getCode() {
213        return attCode.getCode();
214    }
215
216    /**
217     * Gets the exception table.
218     *
219     * @return {@code non-null;} the exception table
220     */
221    public ByteCatchList getCatches() {
222        return attCode.getCatches();
223    }
224
225    /**
226     * Gets the line number list.
227     *
228     * @return {@code non-null;} the line number list
229     */
230    public LineNumberList getLineNumbers() {
231        return lineNumbers;
232    }
233
234    /**
235     * Gets the local variable list.
236     *
237     * @return {@code non-null;} the local variable list
238     */
239    public LocalVariableList getLocalVariables() {
240        return localVariables;
241    }
242
243    /**
244     * Returns a {@link SourcePosition} instance corresponding to the
245     * given bytecode offset.
246     *
247     * @param offset {@code >= 0;} the bytecode offset
248     * @return {@code non-null;} an appropriate instance
249     */
250    public SourcePosition makeSourcePosistion(int offset) {
251        return new SourcePosition(sourceFile, offset,
252                                  lineNumbers.pcToLine(offset));
253    }
254}
255