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.dex.file; 18 19import com.android.dex.Leb128; 20import com.android.dx.dex.code.DalvCode; 21import com.android.dx.rop.code.AccessFlags; 22import com.android.dx.rop.cst.CstMethodRef; 23import com.android.dx.rop.cst.CstString; 24import com.android.dx.rop.type.TypeList; 25import com.android.dx.util.AnnotatedOutput; 26import com.android.dx.util.Hex; 27import java.io.PrintWriter; 28 29/** 30 * Class that representats a method of a class. 31 */ 32public final class EncodedMethod extends EncodedMember 33 implements Comparable<EncodedMethod> { 34 /** {@code non-null;} constant for the method */ 35 private final CstMethodRef method; 36 37 /** 38 * {@code null-ok;} code for the method, if the method is neither 39 * {@code abstract} nor {@code native} 40 */ 41 private final CodeItem code; 42 43 /** 44 * Constructs an instance. 45 * 46 * @param method {@code non-null;} constant for the method 47 * @param accessFlags access flags 48 * @param code {@code null-ok;} code for the method, if it is neither 49 * {@code abstract} nor {@code native} 50 * @param throwsList {@code non-null;} list of possibly-thrown exceptions, 51 * just used in generating debugging output (listings) 52 */ 53 public EncodedMethod(CstMethodRef method, int accessFlags, 54 DalvCode code, TypeList throwsList) { 55 super(accessFlags); 56 57 if (method == null) { 58 throw new NullPointerException("method == null"); 59 } 60 61 this.method = method; 62 63 if (code == null) { 64 this.code = null; 65 } else { 66 boolean isStatic = (accessFlags & AccessFlags.ACC_STATIC) != 0; 67 this.code = new CodeItem(method, code, isStatic, throwsList); 68 } 69 } 70 71 /** {@inheritDoc} */ 72 @Override 73 public boolean equals(Object other) { 74 if (! (other instanceof EncodedMethod)) { 75 return false; 76 } 77 78 return compareTo((EncodedMethod) other) == 0; 79 } 80 81 /** 82 * {@inheritDoc} 83 * 84 * <p><b>Note:</b> This compares the method constants only, 85 * ignoring any associated code, because it should never be the 86 * case that two different items with the same method constant 87 * ever appear in the same list (or same file, even).</p> 88 */ 89 @Override 90 public int compareTo(EncodedMethod other) { 91 return method.compareTo(other.method); 92 } 93 94 /** {@inheritDoc} */ 95 @Override 96 public String toString() { 97 StringBuilder sb = new StringBuilder(100); 98 99 sb.append(getClass().getName()); 100 sb.append('{'); 101 sb.append(Hex.u2(getAccessFlags())); 102 sb.append(' '); 103 sb.append(method); 104 105 if (code != null) { 106 sb.append(' '); 107 sb.append(code); 108 } 109 110 sb.append('}'); 111 112 return sb.toString(); 113 } 114 115 /** {@inheritDoc} */ 116 @Override 117 public void addContents(DexFile file) { 118 MethodIdsSection methodIds = file.getMethodIds(); 119 MixedItemSection wordData = file.getWordData(); 120 121 methodIds.intern(method); 122 123 if (code != null) { 124 wordData.add(code); 125 } 126 } 127 128 /** {@inheritDoc} */ 129 @Override 130 public final String toHuman() { 131 return method.toHuman(); 132 } 133 134 /** {@inheritDoc} */ 135 @Override 136 public final CstString getName() { 137 return method.getNat().getName(); 138 } 139 140 /** {@inheritDoc} */ 141 @Override 142 public void debugPrint(PrintWriter out, boolean verbose) { 143 if (code == null) { 144 out.println(getRef().toHuman() + ": abstract or native"); 145 } else { 146 code.debugPrint(out, " ", verbose); 147 } 148 } 149 150 /** 151 * Gets the constant for the method. 152 * 153 * @return {@code non-null;} the constant 154 */ 155 public final CstMethodRef getRef() { 156 return method; 157 } 158 159 /** {@inheritDoc} */ 160 @Override 161 public int encode(DexFile file, AnnotatedOutput out, 162 int lastIndex, int dumpSeq) { 163 int methodIdx = file.getMethodIds().indexOf(method); 164 int diff = methodIdx - lastIndex; 165 int accessFlags = getAccessFlags(); 166 int codeOff = OffsettedItem.getAbsoluteOffsetOr0(code); 167 boolean hasCode = (codeOff != 0); 168 boolean shouldHaveCode = (accessFlags & 169 (AccessFlags.ACC_ABSTRACT | AccessFlags.ACC_NATIVE)) == 0; 170 171 /* 172 * Verify that code appears if and only if a method is 173 * declared to have it. 174 */ 175 if (hasCode != shouldHaveCode) { 176 throw new UnsupportedOperationException( 177 "code vs. access_flags mismatch"); 178 } 179 180 if (out.annotates()) { 181 out.annotate(0, String.format(" [%x] %s", dumpSeq, 182 method.toHuman())); 183 out.annotate(Leb128.unsignedLeb128Size(diff), 184 " method_idx: " + Hex.u4(methodIdx)); 185 out.annotate(Leb128.unsignedLeb128Size(accessFlags), 186 " access_flags: " + 187 AccessFlags.methodString(accessFlags)); 188 out.annotate(Leb128.unsignedLeb128Size(codeOff), 189 " code_off: " + Hex.u4(codeOff)); 190 } 191 192 out.writeUleb128(diff); 193 out.writeUleb128(accessFlags); 194 out.writeUleb128(codeOff); 195 196 return methodIdx; 197 } 198} 199