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