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