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