rt/emul/compact/src/main/java/java/lang/invoke/DirectMethodHandle.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Sat, 09 Aug 2014 11:11:13 +0200
branchjdk8-b132
changeset 1646 c880a8a8803b
child 1653 bd151459ee4f
permissions -rw-r--r--
Batch of classes necessary to implement invoke dynamic interfaces. Taken from JDK8 build 132
     1 /*
     2  * Copyright (c) 2008, 2013, 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.misc.Unsafe;
    29 import java.lang.reflect.Method;
    30 import java.util.Arrays;
    31 import sun.invoke.util.VerifyAccess;
    32 import static java.lang.invoke.MethodHandleNatives.Constants.*;
    33 import static java.lang.invoke.LambdaForm.*;
    34 import static java.lang.invoke.MethodTypeForm.*;
    35 import static java.lang.invoke.MethodHandleStatics.*;
    36 import java.lang.ref.WeakReference;
    37 import java.lang.reflect.Field;
    38 import sun.invoke.util.ValueConversions;
    39 import sun.invoke.util.VerifyType;
    40 import sun.invoke.util.Wrapper;
    41 
    42 /**
    43  * The flavor of method handle which implements a constant reference
    44  * to a class member.
    45  * @author jrose
    46  */
    47 class DirectMethodHandle extends MethodHandle {
    48     final MemberName member;
    49 
    50     // Constructors and factory methods in this class *must* be package scoped or private.
    51     private DirectMethodHandle(MethodType mtype, LambdaForm form, MemberName member) {
    52         super(mtype, form);
    53         if (!member.isResolved())  throw new InternalError();
    54 
    55         if (member.getDeclaringClass().isInterface() &&
    56                 member.isMethod() && !member.isAbstract()) {
    57             // Check for corner case: invokeinterface of Object method
    58             MemberName m = new MemberName(Object.class, member.getName(), member.getMethodType(), member.getReferenceKind());
    59             m = MemberName.getFactory().resolveOrNull(m.getReferenceKind(), m, null);
    60             if (m != null && m.isPublic()) {
    61                 member = m;
    62             }
    63         }
    64 
    65         this.member = member;
    66     }
    67 
    68     // Factory methods:
    69     static DirectMethodHandle make(byte refKind, Class<?> receiver, MemberName member) {
    70         MethodType mtype = member.getMethodOrFieldType();
    71         if (!member.isStatic()) {
    72             if (!member.getDeclaringClass().isAssignableFrom(receiver) || member.isConstructor())
    73                 throw new InternalError(member.toString());
    74             mtype = mtype.insertParameterTypes(0, receiver);
    75         }
    76         if (!member.isField()) {
    77             if (refKind == REF_invokeSpecial) {
    78                 member = member.asSpecial();
    79                 LambdaForm lform = preparedLambdaForm(member);
    80                 return new Special(mtype, lform, member);
    81             } else {
    82                 LambdaForm lform = preparedLambdaForm(member);
    83                 return new DirectMethodHandle(mtype, lform, member);
    84             }
    85         } else {
    86             LambdaForm lform = preparedFieldLambdaForm(member);
    87             if (member.isStatic()) {
    88                 long offset = MethodHandleNatives.staticFieldOffset(member);
    89                 Object base = MethodHandleNatives.staticFieldBase(member);
    90                 return new StaticAccessor(mtype, lform, member, base, offset);
    91             } else {
    92                 long offset = MethodHandleNatives.objectFieldOffset(member);
    93                 assert(offset == (int)offset);
    94                 return new Accessor(mtype, lform, member, (int)offset);
    95             }
    96         }
    97     }
    98     static DirectMethodHandle make(Class<?> receiver, MemberName member) {
    99         byte refKind = member.getReferenceKind();
   100         if (refKind == REF_invokeSpecial)
   101             refKind =  REF_invokeVirtual;
   102         return make(refKind, receiver, member);
   103     }
   104     static DirectMethodHandle make(MemberName member) {
   105         if (member.isConstructor())
   106             return makeAllocator(member);
   107         return make(member.getDeclaringClass(), member);
   108     }
   109     static DirectMethodHandle make(Method method) {
   110         return make(method.getDeclaringClass(), new MemberName(method));
   111     }
   112     static DirectMethodHandle make(Field field) {
   113         return make(field.getDeclaringClass(), new MemberName(field));
   114     }
   115     private static DirectMethodHandle makeAllocator(MemberName ctor) {
   116         assert(ctor.isConstructor() && ctor.getName().equals("<init>"));
   117         Class<?> instanceClass = ctor.getDeclaringClass();
   118         ctor = ctor.asConstructor();
   119         assert(ctor.isConstructor() && ctor.getReferenceKind() == REF_newInvokeSpecial) : ctor;
   120         MethodType mtype = ctor.getMethodType().changeReturnType(instanceClass);
   121         LambdaForm lform = preparedLambdaForm(ctor);
   122         MemberName init = ctor.asSpecial();
   123         assert(init.getMethodType().returnType() == void.class);
   124         return new Constructor(mtype, lform, ctor, init, instanceClass);
   125     }
   126 
   127     @Override
   128     MethodHandle copyWith(MethodType mt, LambdaForm lf) {
   129         return new DirectMethodHandle(mt, lf, member);
   130     }
   131 
   132     @Override
   133     String internalProperties() {
   134         return "/DMH="+member.toString();
   135     }
   136 
   137     //// Implementation methods.
   138     @Override
   139     MethodHandle viewAsType(MethodType newType) {
   140         return new DirectMethodHandle(newType, form, member);
   141     }
   142     @Override
   143     @ForceInline
   144     MemberName internalMemberName() {
   145         return member;
   146     }
   147 
   148     @Override
   149     MethodHandle bindArgument(int pos, char basicType, Object value) {
   150         // If the member needs dispatching, do so.
   151         if (pos == 0 && basicType == 'L') {
   152             DirectMethodHandle concrete = maybeRebind(value);
   153             if (concrete != null)
   154                 return concrete.bindReceiver(value);
   155         }
   156         return super.bindArgument(pos, basicType, value);
   157     }
   158 
   159     @Override
   160     MethodHandle bindReceiver(Object receiver) {
   161         // If the member needs dispatching, do so.
   162         DirectMethodHandle concrete = maybeRebind(receiver);
   163         if (concrete != null)
   164             return concrete.bindReceiver(receiver);
   165         return super.bindReceiver(receiver);
   166     }
   167 
   168     private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory();
   169 
   170     private DirectMethodHandle maybeRebind(Object receiver) {
   171         if (receiver != null) {
   172             switch (member.getReferenceKind()) {
   173             case REF_invokeInterface:
   174             case REF_invokeVirtual:
   175                 // Pre-dispatch the member.
   176                 Class<?> concreteClass = receiver.getClass();
   177                 MemberName concrete = new MemberName(concreteClass, member.getName(), member.getMethodType(), REF_invokeSpecial);
   178                 concrete = IMPL_NAMES.resolveOrNull(REF_invokeSpecial, concrete, concreteClass);
   179                 if (concrete != null)
   180                     return new DirectMethodHandle(type(), preparedLambdaForm(concrete), concrete);
   181                 break;
   182             }
   183         }
   184         return null;
   185     }
   186 
   187     /**
   188      * Create a LF which can invoke the given method.
   189      * Cache and share this structure among all methods with
   190      * the same basicType and refKind.
   191      */
   192     private static LambdaForm preparedLambdaForm(MemberName m) {
   193         assert(m.isInvocable()) : m;  // call preparedFieldLambdaForm instead
   194         MethodType mtype = m.getInvocationType().basicType();
   195         assert(!m.isMethodHandleInvoke() || "invokeBasic".equals(m.getName())) : m;
   196         int which;
   197         switch (m.getReferenceKind()) {
   198         case REF_invokeVirtual:    which = LF_INVVIRTUAL;    break;
   199         case REF_invokeStatic:     which = LF_INVSTATIC;     break;
   200         case REF_invokeSpecial:    which = LF_INVSPECIAL;    break;
   201         case REF_invokeInterface:  which = LF_INVINTERFACE;  break;
   202         case REF_newInvokeSpecial: which = LF_NEWINVSPECIAL; break;
   203         default:  throw new InternalError(m.toString());
   204         }
   205         if (which == LF_INVSTATIC && shouldBeInitialized(m)) {
   206             // precompute the barrier-free version:
   207             preparedLambdaForm(mtype, which);
   208             which = LF_INVSTATIC_INIT;
   209         }
   210         LambdaForm lform = preparedLambdaForm(mtype, which);
   211         maybeCompile(lform, m);
   212         assert(lform.methodType().dropParameterTypes(0, 1)
   213                 .equals(m.getInvocationType().basicType()))
   214                 : Arrays.asList(m, m.getInvocationType().basicType(), lform, lform.methodType());
   215         return lform;
   216     }
   217 
   218     private static LambdaForm preparedLambdaForm(MethodType mtype, int which) {
   219         LambdaForm lform = mtype.form().cachedLambdaForm(which);
   220         if (lform != null)  return lform;
   221         lform = makePreparedLambdaForm(mtype, which);
   222         return mtype.form().setCachedLambdaForm(which, lform);
   223     }
   224 
   225     private static LambdaForm makePreparedLambdaForm(MethodType mtype, int which) {
   226         boolean needsInit = (which == LF_INVSTATIC_INIT);
   227         boolean doesAlloc = (which == LF_NEWINVSPECIAL);
   228         String linkerName, lambdaName;
   229         switch (which) {
   230         case LF_INVVIRTUAL:    linkerName = "linkToVirtual";    lambdaName = "DMH.invokeVirtual";    break;
   231         case LF_INVSTATIC:     linkerName = "linkToStatic";     lambdaName = "DMH.invokeStatic";     break;
   232         case LF_INVSTATIC_INIT:linkerName = "linkToStatic";     lambdaName = "DMH.invokeStaticInit"; break;
   233         case LF_INVSPECIAL:    linkerName = "linkToSpecial";    lambdaName = "DMH.invokeSpecial";    break;
   234         case LF_INVINTERFACE:  linkerName = "linkToInterface";  lambdaName = "DMH.invokeInterface";  break;
   235         case LF_NEWINVSPECIAL: linkerName = "linkToSpecial";    lambdaName = "DMH.newInvokeSpecial"; break;
   236         default:  throw new InternalError("which="+which);
   237         }
   238         MethodType mtypeWithArg = mtype.appendParameterTypes(MemberName.class);
   239         if (doesAlloc)
   240             mtypeWithArg = mtypeWithArg
   241                     .insertParameterTypes(0, Object.class)  // insert newly allocated obj
   242                     .changeReturnType(void.class);          // <init> returns void
   243         MemberName linker = new MemberName(MethodHandle.class, linkerName, mtypeWithArg, REF_invokeStatic);
   244         try {
   245             linker = IMPL_NAMES.resolveOrFail(REF_invokeStatic, linker, null, NoSuchMethodException.class);
   246         } catch (ReflectiveOperationException ex) {
   247             throw newInternalError(ex);
   248         }
   249         final int DMH_THIS    = 0;
   250         final int ARG_BASE    = 1;
   251         final int ARG_LIMIT   = ARG_BASE + mtype.parameterCount();
   252         int nameCursor = ARG_LIMIT;
   253         final int NEW_OBJ     = (doesAlloc ? nameCursor++ : -1);
   254         final int GET_MEMBER  = nameCursor++;
   255         final int LINKER_CALL = nameCursor++;
   256         Name[] names = arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
   257         assert(names.length == nameCursor);
   258         if (doesAlloc) {
   259             // names = { argx,y,z,... new C, init method }
   260             names[NEW_OBJ] = new Name(Lazy.NF_allocateInstance, names[DMH_THIS]);
   261             names[GET_MEMBER] = new Name(Lazy.NF_constructorMethod, names[DMH_THIS]);
   262         } else if (needsInit) {
   263             names[GET_MEMBER] = new Name(Lazy.NF_internalMemberNameEnsureInit, names[DMH_THIS]);
   264         } else {
   265             names[GET_MEMBER] = new Name(Lazy.NF_internalMemberName, names[DMH_THIS]);
   266         }
   267         Object[] outArgs = Arrays.copyOfRange(names, ARG_BASE, GET_MEMBER+1, Object[].class);
   268         assert(outArgs[outArgs.length-1] == names[GET_MEMBER]);  // look, shifted args!
   269         int result = LambdaForm.LAST_RESULT;
   270         if (doesAlloc) {
   271             assert(outArgs[outArgs.length-2] == names[NEW_OBJ]);  // got to move this one
   272             System.arraycopy(outArgs, 0, outArgs, 1, outArgs.length-2);
   273             outArgs[0] = names[NEW_OBJ];
   274             result = NEW_OBJ;
   275         }
   276         names[LINKER_CALL] = new Name(linker, outArgs);
   277         lambdaName += "_" + LambdaForm.basicTypeSignature(mtype);
   278         LambdaForm lform = new LambdaForm(lambdaName, ARG_LIMIT, names, result);
   279         // This is a tricky bit of code.  Don't send it through the LF interpreter.
   280         lform.compileToBytecode();
   281         return lform;
   282     }
   283 
   284     private static void maybeCompile(LambdaForm lform, MemberName m) {
   285         if (VerifyAccess.isSamePackage(m.getDeclaringClass(), MethodHandle.class))
   286             // Help along bootstrapping...
   287             lform.compileToBytecode();
   288     }
   289 
   290     /** Static wrapper for DirectMethodHandle.internalMemberName. */
   291     @ForceInline
   292     /*non-public*/ static Object internalMemberName(Object mh) {
   293         return ((DirectMethodHandle)mh).member;
   294     }
   295 
   296     /** Static wrapper for DirectMethodHandle.internalMemberName.
   297      * This one also forces initialization.
   298      */
   299     /*non-public*/ static Object internalMemberNameEnsureInit(Object mh) {
   300         DirectMethodHandle dmh = (DirectMethodHandle)mh;
   301         dmh.ensureInitialized();
   302         return dmh.member;
   303     }
   304 
   305     /*non-public*/ static
   306     boolean shouldBeInitialized(MemberName member) {
   307         switch (member.getReferenceKind()) {
   308         case REF_invokeStatic:
   309         case REF_getStatic:
   310         case REF_putStatic:
   311         case REF_newInvokeSpecial:
   312             break;
   313         default:
   314             // No need to initialize the class on this kind of member.
   315             return false;
   316         }
   317         Class<?> cls = member.getDeclaringClass();
   318         if (cls == ValueConversions.class ||
   319             cls == MethodHandleImpl.class ||
   320             cls == Invokers.class) {
   321             // These guys have lots of <clinit> DMH creation but we know
   322             // the MHs will not be used until the system is booted.
   323             return false;
   324         }
   325         if (VerifyAccess.isSamePackage(MethodHandle.class, cls) ||
   326             VerifyAccess.isSamePackage(ValueConversions.class, cls)) {
   327             // It is a system class.  It is probably in the process of
   328             // being initialized, but we will help it along just to be safe.
   329             if (UNSAFE.shouldBeInitialized(cls)) {
   330                 UNSAFE.ensureClassInitialized(cls);
   331             }
   332             return false;
   333         }
   334         return UNSAFE.shouldBeInitialized(cls);
   335     }
   336 
   337     private static class EnsureInitialized extends ClassValue<WeakReference<Thread>> {
   338         @Override
   339         protected WeakReference<Thread> computeValue(Class<?> type) {
   340             UNSAFE.ensureClassInitialized(type);
   341             if (UNSAFE.shouldBeInitialized(type))
   342                 // If the previous call didn't block, this can happen.
   343                 // We are executing inside <clinit>.
   344                 return new WeakReference<>(Thread.currentThread());
   345             return null;
   346         }
   347         static final EnsureInitialized INSTANCE = new EnsureInitialized();
   348     }
   349 
   350     private void ensureInitialized() {
   351         if (checkInitialized(member)) {
   352             // The coast is clear.  Delete the <clinit> barrier.
   353             if (member.isField())
   354                 updateForm(preparedFieldLambdaForm(member));
   355             else
   356                 updateForm(preparedLambdaForm(member));
   357         }
   358     }
   359     private static boolean checkInitialized(MemberName member) {
   360         Class<?> defc = member.getDeclaringClass();
   361         WeakReference<Thread> ref = EnsureInitialized.INSTANCE.get(defc);
   362         if (ref == null) {
   363             return true;  // the final state
   364         }
   365         Thread clinitThread = ref.get();
   366         // Somebody may still be running defc.<clinit>.
   367         if (clinitThread == Thread.currentThread()) {
   368             // If anybody is running defc.<clinit>, it is this thread.
   369             if (UNSAFE.shouldBeInitialized(defc))
   370                 // Yes, we are running it; keep the barrier for now.
   371                 return false;
   372         } else {
   373             // We are in a random thread.  Block.
   374             UNSAFE.ensureClassInitialized(defc);
   375         }
   376         assert(!UNSAFE.shouldBeInitialized(defc));
   377         // put it into the final state
   378         EnsureInitialized.INSTANCE.remove(defc);
   379         return true;
   380     }
   381 
   382     /*non-public*/ static void ensureInitialized(Object mh) {
   383         ((DirectMethodHandle)mh).ensureInitialized();
   384     }
   385 
   386     /** This subclass represents invokespecial instructions. */
   387     static class Special extends DirectMethodHandle {
   388         private Special(MethodType mtype, LambdaForm form, MemberName member) {
   389             super(mtype, form, member);
   390         }
   391         @Override
   392         boolean isInvokeSpecial() {
   393             return true;
   394         }
   395         @Override
   396         MethodHandle viewAsType(MethodType newType) {
   397             return new Special(newType, form, member);
   398         }
   399     }
   400 
   401     /** This subclass handles constructor references. */
   402     static class Constructor extends DirectMethodHandle {
   403         final MemberName initMethod;
   404         final Class<?>   instanceClass;
   405 
   406         private Constructor(MethodType mtype, LambdaForm form, MemberName constructor,
   407                             MemberName initMethod, Class<?> instanceClass) {
   408             super(mtype, form, constructor);
   409             this.initMethod = initMethod;
   410             this.instanceClass = instanceClass;
   411             assert(initMethod.isResolved());
   412         }
   413         @Override
   414         MethodHandle viewAsType(MethodType newType) {
   415             return new Constructor(newType, form, member, initMethod, instanceClass);
   416         }
   417     }
   418 
   419     /*non-public*/ static Object constructorMethod(Object mh) {
   420         Constructor dmh = (Constructor)mh;
   421         return dmh.initMethod;
   422     }
   423 
   424     /*non-public*/ static Object allocateInstance(Object mh) throws InstantiationException {
   425         Constructor dmh = (Constructor)mh;
   426         return UNSAFE.allocateInstance(dmh.instanceClass);
   427     }
   428 
   429     /** This subclass handles non-static field references. */
   430     static class Accessor extends DirectMethodHandle {
   431         final Class<?> fieldType;
   432         final int      fieldOffset;
   433         private Accessor(MethodType mtype, LambdaForm form, MemberName member,
   434                          int fieldOffset) {
   435             super(mtype, form, member);
   436             this.fieldType   = member.getFieldType();
   437             this.fieldOffset = fieldOffset;
   438         }
   439 
   440         @Override Object checkCast(Object obj) {
   441             return fieldType.cast(obj);
   442         }
   443         @Override
   444         MethodHandle viewAsType(MethodType newType) {
   445             return new Accessor(newType, form, member, fieldOffset);
   446         }
   447     }
   448 
   449     @ForceInline
   450     /*non-public*/ static long fieldOffset(Object accessorObj) {
   451         // Note: We return a long because that is what Unsafe.getObject likes.
   452         // We store a plain int because it is more compact.
   453         return ((Accessor)accessorObj).fieldOffset;
   454     }
   455 
   456     @ForceInline
   457     /*non-public*/ static Object checkBase(Object obj) {
   458         // Note that the object's class has already been verified,
   459         // since the parameter type of the Accessor method handle
   460         // is either member.getDeclaringClass or a subclass.
   461         // This was verified in DirectMethodHandle.make.
   462         // Therefore, the only remaining check is for null.
   463         // Since this check is *not* guaranteed by Unsafe.getInt
   464         // and its siblings, we need to make an explicit one here.
   465         obj.getClass();  // maybe throw NPE
   466         return obj;
   467     }
   468 
   469     /** This subclass handles static field references. */
   470     static class StaticAccessor extends DirectMethodHandle {
   471         final private Class<?> fieldType;
   472         final private Object   staticBase;
   473         final private long     staticOffset;
   474 
   475         private StaticAccessor(MethodType mtype, LambdaForm form, MemberName member,
   476                                Object staticBase, long staticOffset) {
   477             super(mtype, form, member);
   478             this.fieldType    = member.getFieldType();
   479             this.staticBase   = staticBase;
   480             this.staticOffset = staticOffset;
   481         }
   482 
   483         @Override Object checkCast(Object obj) {
   484             return fieldType.cast(obj);
   485         }
   486         @Override
   487         MethodHandle viewAsType(MethodType newType) {
   488             return new StaticAccessor(newType, form, member, staticBase, staticOffset);
   489         }
   490     }
   491 
   492     @ForceInline
   493     /*non-public*/ static Object nullCheck(Object obj) {
   494         obj.getClass();
   495         return obj;
   496     }
   497 
   498     @ForceInline
   499     /*non-public*/ static Object staticBase(Object accessorObj) {
   500         return ((StaticAccessor)accessorObj).staticBase;
   501     }
   502 
   503     @ForceInline
   504     /*non-public*/ static long staticOffset(Object accessorObj) {
   505         return ((StaticAccessor)accessorObj).staticOffset;
   506     }
   507 
   508     @ForceInline
   509     /*non-public*/ static Object checkCast(Object mh, Object obj) {
   510         return ((DirectMethodHandle) mh).checkCast(obj);
   511     }
   512 
   513     Object checkCast(Object obj) {
   514         return member.getReturnType().cast(obj);
   515     }
   516 
   517     // Caching machinery for field accessors:
   518     private static byte
   519             AF_GETFIELD        = 0,
   520             AF_PUTFIELD        = 1,
   521             AF_GETSTATIC       = 2,
   522             AF_PUTSTATIC       = 3,
   523             AF_GETSTATIC_INIT  = 4,
   524             AF_PUTSTATIC_INIT  = 5,
   525             AF_LIMIT           = 6;
   526     // Enumerate the different field kinds using Wrapper,
   527     // with an extra case added for checked references.
   528     private static int
   529             FT_LAST_WRAPPER    = Wrapper.values().length-1,
   530             FT_UNCHECKED_REF   = Wrapper.OBJECT.ordinal(),
   531             FT_CHECKED_REF     = FT_LAST_WRAPPER+1,
   532             FT_LIMIT           = FT_LAST_WRAPPER+2;
   533     private static int afIndex(byte formOp, boolean isVolatile, int ftypeKind) {
   534         return ((formOp * FT_LIMIT * 2)
   535                 + (isVolatile ? FT_LIMIT : 0)
   536                 + ftypeKind);
   537     }
   538     private static final LambdaForm[] ACCESSOR_FORMS
   539             = new LambdaForm[afIndex(AF_LIMIT, false, 0)];
   540     private static int ftypeKind(Class<?> ftype) {
   541         if (ftype.isPrimitive())
   542             return Wrapper.forPrimitiveType(ftype).ordinal();
   543         else if (VerifyType.isNullReferenceConversion(Object.class, ftype))
   544             return FT_UNCHECKED_REF;
   545         else
   546             return FT_CHECKED_REF;
   547     }
   548 
   549     /**
   550      * Create a LF which can access the given field.
   551      * Cache and share this structure among all fields with
   552      * the same basicType and refKind.
   553      */
   554     private static LambdaForm preparedFieldLambdaForm(MemberName m) {
   555         Class<?> ftype = m.getFieldType();
   556         boolean isVolatile = m.isVolatile();
   557         byte formOp;
   558         switch (m.getReferenceKind()) {
   559         case REF_getField:      formOp = AF_GETFIELD;    break;
   560         case REF_putField:      formOp = AF_PUTFIELD;    break;
   561         case REF_getStatic:     formOp = AF_GETSTATIC;   break;
   562         case REF_putStatic:     formOp = AF_PUTSTATIC;   break;
   563         default:  throw new InternalError(m.toString());
   564         }
   565         if (shouldBeInitialized(m)) {
   566             // precompute the barrier-free version:
   567             preparedFieldLambdaForm(formOp, isVolatile, ftype);
   568             assert((AF_GETSTATIC_INIT - AF_GETSTATIC) ==
   569                    (AF_PUTSTATIC_INIT - AF_PUTSTATIC));
   570             formOp += (AF_GETSTATIC_INIT - AF_GETSTATIC);
   571         }
   572         LambdaForm lform = preparedFieldLambdaForm(formOp, isVolatile, ftype);
   573         maybeCompile(lform, m);
   574         assert(lform.methodType().dropParameterTypes(0, 1)
   575                 .equals(m.getInvocationType().basicType()))
   576                 : Arrays.asList(m, m.getInvocationType().basicType(), lform, lform.methodType());
   577         return lform;
   578     }
   579     private static LambdaForm preparedFieldLambdaForm(byte formOp, boolean isVolatile, Class<?> ftype) {
   580         int afIndex = afIndex(formOp, isVolatile, ftypeKind(ftype));
   581         LambdaForm lform = ACCESSOR_FORMS[afIndex];
   582         if (lform != null)  return lform;
   583         lform = makePreparedFieldLambdaForm(formOp, isVolatile, ftypeKind(ftype));
   584         ACCESSOR_FORMS[afIndex] = lform;  // don't bother with a CAS
   585         return lform;
   586     }
   587 
   588     private static LambdaForm makePreparedFieldLambdaForm(byte formOp, boolean isVolatile, int ftypeKind) {
   589         boolean isGetter  = (formOp & 1) == (AF_GETFIELD & 1);
   590         boolean isStatic  = (formOp >= AF_GETSTATIC);
   591         boolean needsInit = (formOp >= AF_GETSTATIC_INIT);
   592         boolean needsCast = (ftypeKind == FT_CHECKED_REF);
   593         Wrapper fw = (needsCast ? Wrapper.OBJECT : Wrapper.values()[ftypeKind]);
   594         Class<?> ft = fw.primitiveType();
   595         assert(ftypeKind(needsCast ? String.class : ft) == ftypeKind);
   596         String tname  = fw.primitiveSimpleName();
   597         String ctname = Character.toUpperCase(tname.charAt(0)) + tname.substring(1);
   598         if (isVolatile)  ctname += "Volatile";
   599         String getOrPut = (isGetter ? "get" : "put");
   600         String linkerName = (getOrPut + ctname);  // getObject, putIntVolatile, etc.
   601         MethodType linkerType;
   602         if (isGetter)
   603             linkerType = MethodType.methodType(ft, Object.class, long.class);
   604         else
   605             linkerType = MethodType.methodType(void.class, Object.class, long.class, ft);
   606         MemberName linker = new MemberName(Unsafe.class, linkerName, linkerType, REF_invokeVirtual);
   607         try {
   608             linker = IMPL_NAMES.resolveOrFail(REF_invokeVirtual, linker, null, NoSuchMethodException.class);
   609         } catch (ReflectiveOperationException ex) {
   610             throw newInternalError(ex);
   611         }
   612 
   613         // What is the external type of the lambda form?
   614         MethodType mtype;
   615         if (isGetter)
   616             mtype = MethodType.methodType(ft);
   617         else
   618             mtype = MethodType.methodType(void.class, ft);
   619         mtype = mtype.basicType();  // erase short to int, etc.
   620         if (!isStatic)
   621             mtype = mtype.insertParameterTypes(0, Object.class);
   622         final int DMH_THIS  = 0;
   623         final int ARG_BASE  = 1;
   624         final int ARG_LIMIT = ARG_BASE + mtype.parameterCount();
   625         // if this is for non-static access, the base pointer is stored at this index:
   626         final int OBJ_BASE  = isStatic ? -1 : ARG_BASE;
   627         // if this is for write access, the value to be written is stored at this index:
   628         final int SET_VALUE  = isGetter ? -1 : ARG_LIMIT - 1;
   629         int nameCursor = ARG_LIMIT;
   630         final int F_HOLDER  = (isStatic ? nameCursor++ : -1);  // static base if any
   631         final int F_OFFSET  = nameCursor++;  // Either static offset or field offset.
   632         final int OBJ_CHECK = (OBJ_BASE >= 0 ? nameCursor++ : -1);
   633         final int INIT_BAR  = (needsInit ? nameCursor++ : -1);
   634         final int PRE_CAST  = (needsCast && !isGetter ? nameCursor++ : -1);
   635         final int LINKER_CALL = nameCursor++;
   636         final int POST_CAST = (needsCast && isGetter ? nameCursor++ : -1);
   637         final int RESULT    = nameCursor-1;  // either the call or the cast
   638         Name[] names = arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
   639         if (needsInit)
   640             names[INIT_BAR] = new Name(Lazy.NF_ensureInitialized, names[DMH_THIS]);
   641         if (needsCast && !isGetter)
   642             names[PRE_CAST] = new Name(Lazy.NF_checkCast, names[DMH_THIS], names[SET_VALUE]);
   643         Object[] outArgs = new Object[1 + linkerType.parameterCount()];
   644         assert(outArgs.length == (isGetter ? 3 : 4));
   645         outArgs[0] = UNSAFE;
   646         if (isStatic) {
   647             outArgs[1] = names[F_HOLDER]  = new Name(Lazy.NF_staticBase, names[DMH_THIS]);
   648             outArgs[2] = names[F_OFFSET]  = new Name(Lazy.NF_staticOffset, names[DMH_THIS]);
   649         } else {
   650             outArgs[1] = names[OBJ_CHECK] = new Name(Lazy.NF_checkBase, names[OBJ_BASE]);
   651             outArgs[2] = names[F_OFFSET]  = new Name(Lazy.NF_fieldOffset, names[DMH_THIS]);
   652         }
   653         if (!isGetter) {
   654             outArgs[3] = (needsCast ? names[PRE_CAST] : names[SET_VALUE]);
   655         }
   656         for (Object a : outArgs)  assert(a != null);
   657         names[LINKER_CALL] = new Name(linker, outArgs);
   658         if (needsCast && isGetter)
   659             names[POST_CAST] = new Name(Lazy.NF_checkCast, names[DMH_THIS], names[LINKER_CALL]);
   660         for (Name n : names)  assert(n != null);
   661         String fieldOrStatic = (isStatic ? "Static" : "Field");
   662         String lambdaName = (linkerName + fieldOrStatic);  // significant only for debugging
   663         if (needsCast)  lambdaName += "Cast";
   664         if (needsInit)  lambdaName += "Init";
   665         return new LambdaForm(lambdaName, ARG_LIMIT, names, RESULT);
   666     }
   667 
   668     /**
   669      * Pre-initialized NamedFunctions for bootstrapping purposes.
   670      * Factored in an inner class to delay initialization until first usage.
   671      */
   672     private static class Lazy {
   673         static final NamedFunction
   674                 NF_internalMemberName,
   675                 NF_internalMemberNameEnsureInit,
   676                 NF_ensureInitialized,
   677                 NF_fieldOffset,
   678                 NF_checkBase,
   679                 NF_staticBase,
   680                 NF_staticOffset,
   681                 NF_checkCast,
   682                 NF_allocateInstance,
   683                 NF_constructorMethod;
   684         static {
   685             try {
   686                 NamedFunction nfs[] = {
   687                         NF_internalMemberName = new NamedFunction(DirectMethodHandle.class
   688                                 .getDeclaredMethod("internalMemberName", Object.class)),
   689                         NF_internalMemberNameEnsureInit = new NamedFunction(DirectMethodHandle.class
   690                                 .getDeclaredMethod("internalMemberNameEnsureInit", Object.class)),
   691                         NF_ensureInitialized = new NamedFunction(DirectMethodHandle.class
   692                                 .getDeclaredMethod("ensureInitialized", Object.class)),
   693                         NF_fieldOffset = new NamedFunction(DirectMethodHandle.class
   694                                 .getDeclaredMethod("fieldOffset", Object.class)),
   695                         NF_checkBase = new NamedFunction(DirectMethodHandle.class
   696                                 .getDeclaredMethod("checkBase", Object.class)),
   697                         NF_staticBase = new NamedFunction(DirectMethodHandle.class
   698                                 .getDeclaredMethod("staticBase", Object.class)),
   699                         NF_staticOffset = new NamedFunction(DirectMethodHandle.class
   700                                 .getDeclaredMethod("staticOffset", Object.class)),
   701                         NF_checkCast = new NamedFunction(DirectMethodHandle.class
   702                                 .getDeclaredMethod("checkCast", Object.class, Object.class)),
   703                         NF_allocateInstance = new NamedFunction(DirectMethodHandle.class
   704                                 .getDeclaredMethod("allocateInstance", Object.class)),
   705                         NF_constructorMethod = new NamedFunction(DirectMethodHandle.class
   706                                 .getDeclaredMethod("constructorMethod", Object.class))
   707                 };
   708                 for (NamedFunction nf : nfs) {
   709                     // Each nf must be statically invocable or we get tied up in our bootstraps.
   710                     assert(InvokerBytecodeGenerator.isStaticallyInvocable(nf.member)) : nf;
   711                     nf.resolve();
   712                 }
   713             } catch (ReflectiveOperationException ex) {
   714                 throw newInternalError(ex);
   715             }
   716         }
   717     }
   718 }