ConcreteMethod.java revision ed0fe6c2f310f8c2cc28c35c2b473d8de36db8a4
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, boolean keepLocals) { 76 this(method, cf.getAccessFlags(), cf.getSourceFile(), keepLines, keepLocals); 77 } 78 79 public ConcreteMethod(Method method, int accessFlags, CstUtf8 sourceFile, 80 boolean keepLines, boolean keepLocals) { 81 this.method = method; 82 this.accSuper = (accessFlags & AccessFlags.ACC_SUPER) != 0; 83 this.sourceFile = sourceFile; 84 85 AttributeList attribs = method.getAttributes(); 86 this.attCode = (AttCode) attribs.findFirst(AttCode.ATTRIBUTE_NAME); 87 88 AttributeList codeAttribs = attCode.getAttributes(); 89 90 /* 91 * Combine all LineNumberTable attributes into one, with the 92 * combined result saved into the instance. The following code 93 * isn't particularly efficient for doing merges, but as far 94 * as I know, this situation rarely occurs "in the 95 * wild," so there's not much point in optimizing for it. 96 */ 97 LineNumberList lineNumbers = LineNumberList.EMPTY; 98 if (keepLines) { 99 for (AttLineNumberTable lnt = (AttLineNumberTable) 100 codeAttribs.findFirst(AttLineNumberTable.ATTRIBUTE_NAME); 101 lnt != null; 102 lnt = (AttLineNumberTable) codeAttribs.findNext(lnt)) { 103 lineNumbers = LineNumberList.concat(lineNumbers, 104 lnt.getLineNumbers()); 105 } 106 } 107 this.lineNumbers = lineNumbers; 108 109 LocalVariableList localVariables = LocalVariableList.EMPTY; 110 if (keepLocals) { 111 /* 112 * Do likewise (and with the same caveat) for 113 * LocalVariableTable and LocalVariableTypeTable attributes. 114 * This combines both of these kinds of attribute into a 115 * single LocalVariableList. 116 */ 117 for (AttLocalVariableTable lvt = (AttLocalVariableTable) 118 codeAttribs.findFirst( 119 AttLocalVariableTable.ATTRIBUTE_NAME); 120 lvt != null; 121 lvt = (AttLocalVariableTable) codeAttribs.findNext(lvt)) { 122 localVariables = 123 LocalVariableList.concat(localVariables, 124 lvt.getLocalVariables()); 125 } 126 127 LocalVariableList typeList = LocalVariableList.EMPTY; 128 for (AttLocalVariableTypeTable lvtt = (AttLocalVariableTypeTable) 129 codeAttribs.findFirst( 130 AttLocalVariableTypeTable.ATTRIBUTE_NAME); 131 lvtt != null; 132 lvtt = 133 (AttLocalVariableTypeTable) codeAttribs.findNext(lvtt)) { 134 typeList = 135 LocalVariableList.concat(typeList, 136 lvtt.getLocalVariables()); 137 } 138 139 if (typeList.size() != 0) { 140 localVariables = 141 LocalVariableList.mergeDescriptorsAndSignatures( 142 localVariables, typeList); 143 } 144 } 145 this.localVariables = localVariables; 146 } 147 148 /** {@inheritDoc} */ 149 public CstNat getNat() { 150 return method.getNat(); 151 } 152 153 /** {@inheritDoc} */ 154 public CstUtf8 getName() { 155 return method.getName(); 156 } 157 158 /** {@inheritDoc} */ 159 public CstUtf8 getDescriptor() { 160 return method.getDescriptor(); 161 } 162 163 /** {@inheritDoc} */ 164 public int getAccessFlags() { 165 return method.getAccessFlags(); 166 } 167 168 /** {@inheritDoc} */ 169 public AttributeList getAttributes() { 170 return method.getAttributes(); 171 } 172 173 /** {@inheritDoc} */ 174 public CstType getDefiningClass() { 175 return method.getDefiningClass(); 176 } 177 178 /** {@inheritDoc} */ 179 public Prototype getEffectiveDescriptor() { 180 return method.getEffectiveDescriptor(); 181 } 182 183 /** 184 * Gets whether the class that this method is part of is defined with 185 * {@code ACC_SUPER}. 186 * 187 * @return the {@code ACC_SUPER} value 188 */ 189 public boolean getAccSuper() { 190 return accSuper; 191 } 192 193 /** 194 * Gets the maximum stack size. 195 * 196 * @return {@code >= 0;} the maximum stack size 197 */ 198 public int getMaxStack() { 199 return attCode.getMaxStack(); 200 } 201 202 /** 203 * Gets the number of locals. 204 * 205 * @return {@code >= 0;} the number of locals 206 */ 207 public int getMaxLocals() { 208 return attCode.getMaxLocals(); 209 } 210 211 /** 212 * Gets the bytecode array. 213 * 214 * @return {@code non-null;} the bytecode array 215 */ 216 public BytecodeArray getCode() { 217 return attCode.getCode(); 218 } 219 220 /** 221 * Gets the exception table. 222 * 223 * @return {@code non-null;} the exception table 224 */ 225 public ByteCatchList getCatches() { 226 return attCode.getCatches(); 227 } 228 229 /** 230 * Gets the line number list. 231 * 232 * @return {@code non-null;} the line number list 233 */ 234 public LineNumberList getLineNumbers() { 235 return lineNumbers; 236 } 237 238 /** 239 * Gets the local variable list. 240 * 241 * @return {@code non-null;} the local variable list 242 */ 243 public LocalVariableList getLocalVariables() { 244 return localVariables; 245 } 246 247 /** 248 * Returns a {@link SourcePosition} instance corresponding to the 249 * given bytecode offset. 250 * 251 * @param offset {@code >= 0;} the bytecode offset 252 * @return {@code non-null;} an appropriate instance 253 */ 254 public SourcePosition makeSourcePosistion(int offset) { 255 return new SourcePosition(sourceFile, offset, 256 lineNumbers.pcToLine(offset)); 257 } 258} 259