Home | History | Annotate | Download | only in file
      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 
     17 package com.android.dexgen.dex.file;
     18 
     19 import com.android.dexgen.dex.code.DalvCode;
     20 import com.android.dexgen.rop.code.AccessFlags;
     21 import com.android.dexgen.rop.cst.CstMethodRef;
     22 import com.android.dexgen.rop.cst.CstUtf8;
     23 import com.android.dexgen.rop.type.TypeList;
     24 import com.android.dexgen.util.AnnotatedOutput;
     25 import com.android.dexgen.util.Hex;
     26 import com.android.dexgen.util.Leb128Utils;
     27 
     28 import java.io.PrintWriter;
     29 
     30 /**
     31  * Class that representats a method of a class.
     32  */
     33 public 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