Home | History | Annotate | Download | only in cst
      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.dx.rop.cst;
     18 
     19 import com.android.dx.rop.type.Prototype;
     20 import com.android.dx.rop.type.Type;
     21 import com.android.dx.rop.type.TypeBearer;
     22 
     23 /**
     24  * Base class for constants of "methodish" type.
     25  *
     26  * <p><b>Note:</b> As a {@link TypeBearer}, this class bears the return type
     27  * of the method.</p>
     28  */
     29 public abstract class CstBaseMethodRef
     30         extends CstMemberRef {
     31     /** {@code non-null;} the raw prototype for this method */
     32     private final Prototype prototype;
     33 
     34     /**
     35      * {@code null-ok;} the prototype for this method taken to be an instance
     36      * method, or {@code null} if not yet calculated
     37      */
     38     private Prototype instancePrototype;
     39 
     40     /**
     41      * Constructs an instance.
     42      *
     43      * @param definingClass {@code non-null;} the type of the defining class
     44      * @param nat {@code non-null;} the name-and-type
     45      */
     46     /*package*/ CstBaseMethodRef(CstType definingClass, CstNat nat) {
     47         super(definingClass, nat);
     48 
     49         String descriptor = getNat().getDescriptor().getString();
     50         if (isSignaturePolymorphic()) {
     51             // The prototype for signature polymorphic methods is used to
     52             // construct call-site information and select the true invocation
     53             // target (invoke() or invokeExact(). The prototype is created
     54             // without being interned to avoid polluting the DEX file with
     55             // unused data.
     56             this.prototype = Prototype.fromDescriptor(descriptor);
     57         } else {
     58             this.prototype = Prototype.intern(descriptor);
     59         }
     60         this.instancePrototype = null;
     61     }
     62 
     63     /**
     64      * Gets the raw prototype of this method. This doesn't include a
     65      * {@code this} argument.
     66      *
     67      * @return {@code non-null;} the method prototype
     68      */
     69     public final Prototype getPrototype() {
     70         return prototype;
     71     }
     72 
     73     /**
     74      * Gets the prototype of this method as either a
     75      * {@code static} or instance method. In the case of a
     76      * {@code static} method, this is the same as the raw
     77      * prototype. In the case of an instance method, this has an
     78      * appropriately-typed {@code this} argument as the first
     79      * one.
     80      *
     81      * @param isStatic whether the method should be considered static
     82      * @return {@code non-null;} the method prototype
     83      */
     84     public final Prototype getPrototype(boolean isStatic) {
     85         if (isStatic) {
     86             return prototype;
     87         } else {
     88             if (instancePrototype == null) {
     89                 Type thisType = getDefiningClass().getClassType();
     90                 instancePrototype = prototype.withFirstParameter(thisType);
     91             }
     92             return instancePrototype;
     93         }
     94     }
     95 
     96     /** {@inheritDoc} */
     97     @Override
     98     protected final int compareTo0(Constant other) {
     99         int cmp = super.compareTo0(other);
    100 
    101         if (cmp != 0) {
    102             return cmp;
    103         }
    104 
    105         CstBaseMethodRef otherMethod = (CstBaseMethodRef) other;
    106         return prototype.compareTo(otherMethod.prototype);
    107     }
    108 
    109     /**
    110      * {@inheritDoc}
    111      *
    112      * In this case, this method returns the <i>return type</i> of this method.
    113      *
    114      * @return {@code non-null;} the method's return type
    115      */
    116     public final Type getType() {
    117         return prototype.getReturnType();
    118     }
    119 
    120     /**
    121      * Gets the number of words of parameters required by this
    122      * method's descriptor. Since instances of this class have no way
    123      * to know if they will be used in a {@code static} or
    124      * instance context, one has to indicate this explicitly as an
    125      * argument. This method is just a convenient shorthand for
    126      * {@code getPrototype().getParameterTypes().getWordCount()},
    127      * plus {@code 1} if the method is to be treated as an
    128      * instance method.
    129      *
    130      * @param isStatic whether the method should be considered static
    131      * @return {@code >= 0;} the argument word count
    132      */
    133     public final int getParameterWordCount(boolean isStatic) {
    134         return getPrototype(isStatic).getParameterTypes().getWordCount();
    135     }
    136 
    137     /**
    138      * Gets whether this is a reference to an instance initialization
    139      * method. This is just a convenient shorthand for
    140      * {@code getNat().isInstanceInit()}.
    141      *
    142      * @return {@code true} iff this is a reference to an
    143      * instance initialization method
    144      */
    145     public final boolean isInstanceInit() {
    146         return getNat().isInstanceInit();
    147     }
    148 
    149     /**
    150      * Gets whether this is a reference to a class initialization
    151      * method. This is just a convenient shorthand for
    152      * {@code getNat().isClassInit()}.
    153      *
    154      * @return {@code true} iff this is a reference to an
    155      * instance initialization method
    156      */
    157     public final boolean isClassInit() {
    158         return getNat().isClassInit();
    159     }
    160 
    161     /**
    162      * Get whether this is a reference to a signature polymorphic
    163      * method. This means it is defined in {@code java.lang.invoke.MethodHandle} and
    164      * is either the {@code invoke} or the {@code invokeExact} method.
    165      *
    166      * @return {@code true} iff this is a reference to a
    167      * signature polymorphic method.
    168      */
    169     public final boolean isSignaturePolymorphic() {
    170         return (getDefiningClass().equals(CstType.METHOD_HANDLE) &&
    171                 getNat().isSignaturePolymorphic());
    172     }
    173 }
    174