Home » openjdk-7 » java.lang.invoke » [javadoc | source]

    1   /*
    2    * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Oracle designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Oracle in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22    * or visit www.oracle.com if you need additional information or have any
   23    * questions.
   24    */
   25   
   26   package java.lang.invoke;
   27   
   28   import sun.invoke.util.VerifyType;
   29   import sun.invoke.util.Wrapper;
   30   import static java.lang.invoke.MethodHandleStatics.*;
   31   
   32   /**
   33    * The flavor of method handle which emulates an invoke instruction
   34    * on a predetermined argument.  The JVM dispatches to the correct method
   35    * when the handle is created, not when it is invoked.
   36    * @author jrose
   37    */
   38   class BoundMethodHandle extends MethodHandle {
   39       //MethodHandle vmtarget;           // next BMH or final DMH or methodOop
   40       private final Object argument;     // argument to insert
   41       private final int    vmargslot;    // position at which it is inserted
   42   
   43       // Constructors in this class *must* be package scoped or private.
   44   
   45       /** Bind a direct MH to its receiver (or first ref. argument).
   46        *  The JVM will pre-dispatch the MH if it is not already static.
   47        */
   48       /*non-public*/ BoundMethodHandle(DirectMethodHandle mh, Object argument) {
   49           super(mh.type().dropParameterTypes(0, 1));
   50           // check the type now, once for all:
   51           this.argument = checkReferenceArgument(argument, mh, 0);
   52           this.vmargslot = this.type().parameterSlotCount();
   53           initTarget(mh, 0);
   54       }
   55   
   56       /** Insert an argument into an arbitrary method handle.
   57        *  If argnum is zero, inserts the first argument, etc.
   58        *  The argument type must be a reference.
   59        */
   60       /*non-public*/ BoundMethodHandle(MethodHandle mh, Object argument, int argnum) {
   61           this(mh.type().dropParameterTypes(argnum, argnum+1),
   62                mh, argument, argnum);
   63       }
   64   
   65       /** Insert an argument into an arbitrary method handle.
   66        *  If argnum is zero, inserts the first argument, etc.
   67        */
   68       /*non-public*/ BoundMethodHandle(MethodType type, MethodHandle mh, Object argument, int argnum) {
   69           super(type);
   70           if (mh.type().parameterType(argnum).isPrimitive())
   71               this.argument = bindPrimitiveArgument(argument, mh, argnum);
   72           else {
   73               this.argument = checkReferenceArgument(argument, mh, argnum);
   74           }
   75           this.vmargslot = type.parameterSlotDepth(argnum);
   76           initTarget(mh, argnum);
   77       }
   78   
   79       private void initTarget(MethodHandle mh, int argnum) {
   80           //this.vmtarget = mh;  // maybe updated by JVM
   81           MethodHandleNatives.init(this, mh, argnum);
   82       }
   83   
   84       /** For the AdapterMethodHandle subclass.
   85        */
   86       /*non-public*/ BoundMethodHandle(MethodType type, Object argument, int vmargslot) {
   87           super(type);
   88           this.argument = argument;
   89           this.vmargslot = vmargslot;
   90           assert(this instanceof AdapterMethodHandle);
   91       }
   92   
   93       /** Initialize the current object as a self-bound method handle, binding it
   94        *  as the first argument of the method handle {@code entryPoint}.
   95        *  The invocation type of the resulting method handle will be the
   96        *  same as {@code entryPoint},  except that the first argument
   97        *  type will be dropped.
   98        */
   99       /*non-public*/ BoundMethodHandle(MethodHandle entryPoint) {
  100           super(entryPoint.type().dropParameterTypes(0, 1));
  101           this.argument = this; // kludge; get rid of
  102           this.vmargslot = this.type().parameterSlotDepth(0);
  103           initTarget(entryPoint, 0);
  104       }
  105   
  106       /** Make sure the given {@code argument} can be used as {@code argnum}-th
  107        *  parameter of the given method handle {@code mh}, which must be a reference.
  108        *  <p>
  109        *  If this fails, throw a suitable {@code WrongMethodTypeException},
  110        *  which will prevent the creation of an illegally typed bound
  111        *  method handle.
  112        */
  113       final static Object checkReferenceArgument(Object argument, MethodHandle mh, int argnum) {
  114           Class<?> ptype = mh.type().parameterType(argnum);
  115           if (ptype.isPrimitive()) {
  116               // fail
  117           } else if (argument == null) {
  118               return null;
  119           } else if (VerifyType.isNullReferenceConversion(argument.getClass(), ptype)) {
  120               return argument;
  121           }
  122           throw badBoundArgumentException(argument, mh, argnum);
  123       }
  124   
  125       /** Make sure the given {@code argument} can be used as {@code argnum}-th
  126        *  parameter of the given method handle {@code mh}, which must be a primitive.
  127        *  <p>
  128        *  If this fails, throw a suitable {@code WrongMethodTypeException},
  129        *  which will prevent the creation of an illegally typed bound
  130        *  method handle.
  131        */
  132       final static Object bindPrimitiveArgument(Object argument, MethodHandle mh, int argnum) {
  133           Class<?> ptype = mh.type().parameterType(argnum);
  134           Wrapper  wrap = Wrapper.forPrimitiveType(ptype);
  135           Object   zero  = wrap.zero();
  136           if (zero == null) {
  137               // fail
  138           } else if (argument == null) {
  139               if (ptype != int.class && wrap.isSubwordOrInt())
  140                   return Integer.valueOf(0);
  141               else
  142                   return zero;
  143           } else if (VerifyType.isNullReferenceConversion(argument.getClass(), zero.getClass())) {
  144               if (ptype != int.class && wrap.isSubwordOrInt())
  145                   return Wrapper.INT.wrap(argument);
  146               else
  147                   return argument;
  148           }
  149           throw badBoundArgumentException(argument, mh, argnum);
  150       }
  151   
  152       final static RuntimeException badBoundArgumentException(Object argument, MethodHandle mh, int argnum) {
  153           String atype = (argument == null) ? "null" : argument.getClass().toString();
  154           return new ClassCastException("cannot bind "+atype+" argument to parameter #"+argnum+" of "+mh.type());
  155       }
  156   
  157       @Override
  158       String debugString() {
  159           return addTypeString(baseName(), this);
  160       }
  161   
  162       /** Component of toString() before the type string. */
  163       protected String baseName() {
  164           MethodHandle mh = this;
  165           while (mh instanceof BoundMethodHandle) {
  166               Object info = MethodHandleNatives.getTargetInfo(mh);
  167               if (info instanceof MethodHandle) {
  168                   mh = (MethodHandle) info;
  169               } else {
  170                   String name = null;
  171                   if (info instanceof MemberName)
  172                       name = ((MemberName)info).getName();
  173                   if (name != null)
  174                       return name;
  175                   else
  176                       return noParens(super.toString()); // "invoke", probably
  177               }
  178               assert(mh != this);
  179           }
  180           return noParens(mh.toString());
  181       }
  182   
  183       private static String noParens(String str) {
  184           int paren = str.indexOf('(');
  185           if (paren >= 0) str = str.substring(0, paren);
  186           return str;
  187       }
  188   }

Home » openjdk-7 » java.lang.invoke » [javadoc | source]