Home | History | Annotate | Download | only in invoke
      1 /*
      2  * Copyright 2016 Google Inc.
      3  *
      4  * This code is free software; you can redistribute it and/or modify it
      5  * under the terms of the GNU General Public License version 2 only, as
      6  * published by the Free Software Foundation.  Google designates this
      7  * particular file as subject to the "Classpath" exception as provided
      8  * by Google in the LICENSE file that accompanied this code.
      9  *
     10  * This code is distributed in the hope that it will be useful, but WITHOUT
     11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     13  * version 2 for more details (a copy is included in the LICENSE file that
     14  * accompanied this code).
     15  *
     16  * You should have received a copy of the GNU General Public License version
     17  * 2 along with this work; if not, write to the Free Software Foundation,
     18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     19  */
     20 
     21 package java.lang.invoke;
     22 
     23 import java.lang.reflect.Constructor;
     24 import java.lang.reflect.Member;
     25 import java.lang.reflect.Method;
     26 import java.lang.reflect.Modifier;
     27 
     28 /**
     29  * A method handle that's directly associated with an ArtField or an ArtMethod and
     30  * specifies no additional transformations.
     31  *
     32  * @hide
     33  */
     34 public class MethodHandleImpl extends MethodHandle implements Cloneable {
     35     private HandleInfo info;
     36 
     37     MethodHandleImpl(long artFieldOrMethod, int handleKind, MethodType type) {
     38         super(artFieldOrMethod, handleKind, type);
     39     }
     40 
     41     @Override
     42     public Object clone() throws CloneNotSupportedException {
     43         return super.clone();
     44     }
     45 
     46     MethodHandleInfo reveal() {
     47         if (info == null) {
     48             final Member member = getMemberInternal();
     49             info = new HandleInfo(member, this);
     50         }
     51 
     52         return info;
     53     }
     54 
     55     /**
     56      * Materialize a member from this method handle's ArtField or ArtMethod pointer.
     57      */
     58     public native Member getMemberInternal();
     59 
     60     /**
     61      * Implementation of {@code MethodHandleInfo} in terms of the handle being cracked
     62      * and its corresponding {@code java.lang.reflect.Member}.
     63      */
     64     static class HandleInfo implements MethodHandleInfo {
     65         private final Member member;
     66         private final MethodHandle handle;
     67 
     68         HandleInfo(Member member, MethodHandle handle) {
     69             this.member = member;
     70             this.handle = handle;
     71         }
     72 
     73         @Override
     74         public int getReferenceKind() {
     75             switch (handle.getHandleKind()) {
     76                 case INVOKE_VIRTUAL: {
     77                     if (member.getDeclaringClass().isInterface()) {
     78                         return REF_invokeInterface;
     79                     } else {
     80                         return REF_invokeVirtual;
     81                     }
     82                 }
     83 
     84                 case INVOKE_DIRECT: {
     85                     if (member instanceof Constructor) {
     86                         return REF_newInvokeSpecial;
     87                     } else {
     88                         return REF_invokeSpecial;
     89                     }
     90                 }
     91 
     92                 case INVOKE_SUPER:
     93                     return MethodHandleInfo.REF_invokeSpecial;
     94                 case INVOKE_STATIC:
     95                     return MethodHandleInfo.REF_invokeStatic;
     96                 case IGET:
     97                     return MethodHandleInfo.REF_getField;
     98                 case IPUT:
     99                     return MethodHandleInfo.REF_putField;
    100                 case SGET:
    101                     return MethodHandleInfo.REF_getStatic;
    102                 case SPUT:
    103                     return MethodHandleInfo.REF_putStatic;
    104                 default:
    105                     throw new AssertionError("Unexpected handle kind: " + handle.getHandleKind());
    106             }
    107         }
    108 
    109         @Override
    110         public Class<?> getDeclaringClass() {
    111             return member.getDeclaringClass();
    112         }
    113 
    114         @Override
    115         public String getName() {
    116             if (member instanceof Constructor) {
    117                 return "<init>";
    118             }
    119 
    120             return member.getName();
    121         }
    122 
    123         @Override
    124         public MethodType getMethodType() {
    125             // The "nominal" type of a cracked method handle is the same as the type
    126             // of the handle itself, except in the cases enumerated below.
    127             MethodType handleType = handle.type();
    128 
    129             boolean omitLeadingParam = false;
    130 
    131             // For constructs, the return type is always void.class, and not the type of
    132             // the object returned. We also need to omit the leading reference, which is
    133             // nominally the type of the object being constructed.
    134             if (member instanceof Constructor) {
    135                 handleType = handleType.changeReturnType(void.class);
    136                 omitLeadingParam = true;
    137             }
    138 
    139             // For instance field gets/puts and instance method gets/puts, we omit the
    140             // leading reference parameter to |this|.
    141             switch (handle.getHandleKind()) {
    142                 case IGET:
    143                 case IPUT:
    144                 case INVOKE_INTERFACE:
    145                 case INVOKE_DIRECT:
    146                 case INVOKE_VIRTUAL:
    147                 case INVOKE_SUPER:
    148                     omitLeadingParam = true;
    149             }
    150 
    151             return omitLeadingParam ? handleType.dropParameterTypes(0, 1) : handleType;
    152         }
    153 
    154         @Override
    155         public <T extends Member> T reflectAs(Class<T> expected, MethodHandles.Lookup lookup) {
    156             try {
    157                 lookup.checkAccess(member.getDeclaringClass(), member.getDeclaringClass(),
    158                         member.getModifiers(), member.getName());
    159             } catch (IllegalAccessException exception) {
    160                 throw new IllegalArgumentException("Unable to access member.", exception);
    161             }
    162 
    163             return (T) member;
    164         }
    165 
    166         @Override
    167         public int getModifiers() {
    168             return member.getModifiers();
    169         }
    170     }
    171 }
    172