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 jdk.internal.misc.Unsafe;
29import jdk.internal.vm.annotation.ForceInline;
30import jdk.internal.vm.annotation.Stable;
31import sun.invoke.util.ValueConversions;
32import sun.invoke.util.VerifyAccess;
33import sun.invoke.util.VerifyType;
34import sun.invoke.util.Wrapper;
35
36import java.lang.ref.WeakReference;
37import java.util.Arrays;
38import java.util.Objects;
39
40import static java.lang.invoke.LambdaForm.*;
41import static java.lang.invoke.LambdaForm.Kind.*;
42import static java.lang.invoke.MethodHandleNatives.Constants.*;
43import static java.lang.invoke.MethodHandleStatics.UNSAFE;
44import static java.lang.invoke.MethodHandleStatics.newInternalError;
45import static java.lang.invoke.MethodTypeForm.*;
46
47/**
48 * The flavor of method handle which implements a constant reference
49 * to a class member.
50 * @author jrose
51 */
52class DirectMethodHandle extends MethodHandle {
53    final MemberName member;
54
55    // Constructors and factory methods in this class *must* be package scoped or private.
56    private DirectMethodHandle(MethodType mtype, LambdaForm form, MemberName member) {
57        super(mtype, form);
58        if (!member.isResolved())  throw new InternalError();
59
60        if (member.getDeclaringClass().isInterface() &&
61                member.isMethod() && !member.isAbstract()) {
62            // Check for corner case: invokeinterface of Object method
63            MemberName m = new MemberName(Object.class, member.getName(), member.getMethodType(), member.getReferenceKind());
64            m = MemberName.getFactory().resolveOrNull(m.getReferenceKind(), m, null);
65            if (m != null && m.isPublic()) {
66                assert(member.getReferenceKind() == m.getReferenceKind());  // else this.form is wrong
67                member = m;
68            }
69        }
70
71        this.member = member;
72    }
73
74    // Factory methods:
75    static DirectMethodHandle make(byte refKind, Class<?> receiver, MemberName member) {
76        MethodType mtype = member.getMethodOrFieldType();
77        if (!member.isStatic()) {
78            if (!member.getDeclaringClass().isAssignableFrom(receiver) || member.isConstructor())
79                throw new InternalError(member.toString());
80            mtype = mtype.insertParameterTypes(0, receiver);
81        }
82        if (!member.isField()) {
83            if (refKind == REF_invokeSpecial) {
84                member = member.asSpecial();
85                LambdaForm lform = preparedLambdaForm(member);
86                return new Special(mtype, lform, member);
87            } else {
88                LambdaForm lform = preparedLambdaForm(member);
89                return new DirectMethodHandle(mtype, lform, member);
90            }
91        } else {
92            LambdaForm lform = preparedFieldLambdaForm(member);
93            if (member.isStatic()) {
94                long offset = MethodHandleNatives.staticFieldOffset(member);
95                Object base = MethodHandleNatives.staticFieldBase(member);
96                return new StaticAccessor(mtype, lform, member, base, offset);
97            } else {
98                long offset = MethodHandleNatives.objectFieldOffset(member);
99                assert(offset == (int)offset);
100                return new Accessor(mtype, lform, member, (int)offset);
101            }
102        }
103    }
104    static DirectMethodHandle make(Class<?> receiver, MemberName member) {
105        byte refKind = member.getReferenceKind();
106        if (refKind == REF_invokeSpecial)
107            refKind =  REF_invokeVirtual;
108        return make(refKind, receiver, member);
109    }
110    static DirectMethodHandle make(MemberName member) {
111        if (member.isConstructor())
112            return makeAllocator(member);
113        return make(member.getDeclaringClass(), member);
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    BoundMethodHandle rebind() {
129        return BoundMethodHandle.makeReinvoker(this);
130    }
131
132    @Override
133    MethodHandle copyWith(MethodType mt, LambdaForm lf) {
134        assert(this.getClass() == DirectMethodHandle.class);  // must override in subclasses
135        return new DirectMethodHandle(mt, lf, member);
136    }
137
138    @Override
139    String internalProperties() {
140        return "\n& DMH.MN="+internalMemberName();
141    }
142
143    //// Implementation methods.
144    @Override
145    @ForceInline
146    MemberName internalMemberName() {
147        return member;
148    }
149
150    private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory();
151
152    /**
153     * Create a LF which can invoke the given method.
154     * Cache and share this structure among all methods with
155     * the same basicType and refKind.
156     */
157    private static LambdaForm preparedLambdaForm(MemberName m) {
158        assert(m.isInvocable()) : m;  // call preparedFieldLambdaForm instead
159        MethodType mtype = m.getInvocationType().basicType();
160        assert(!m.isMethodHandleInvoke()) : m;
161        int which;
162        switch (m.getReferenceKind()) {
163        case REF_invokeVirtual:    which = LF_INVVIRTUAL;    break;
164        case REF_invokeStatic:     which = LF_INVSTATIC;     break;
165        case REF_invokeSpecial:    which = LF_INVSPECIAL;    break;
166        case REF_invokeInterface:  which = LF_INVINTERFACE;  break;
167        case REF_newInvokeSpecial: which = LF_NEWINVSPECIAL; break;
168        default:  throw new InternalError(m.toString());
169        }
170        if (which == LF_INVSTATIC && shouldBeInitialized(m)) {
171            // precompute the barrier-free version:
172            preparedLambdaForm(mtype, which);
173            which = LF_INVSTATIC_INIT;
174        }
175        LambdaForm lform = preparedLambdaForm(mtype, which);
176        maybeCompile(lform, m);
177        assert(lform.methodType().dropParameterTypes(0, 1)
178                .equals(m.getInvocationType().basicType()))
179                : Arrays.asList(m, m.getInvocationType().basicType(), lform, lform.methodType());
180        return lform;
181    }
182
183    private static LambdaForm preparedLambdaForm(MethodType mtype, int which) {
184        LambdaForm lform = mtype.form().cachedLambdaForm(which);
185        if (lform != null)  return lform;
186        lform = makePreparedLambdaForm(mtype, which);
187        return mtype.form().setCachedLambdaForm(which, lform);
188    }
189
190    static LambdaForm makePreparedLambdaForm(MethodType mtype, int which) {
191        boolean needsInit = (which == LF_INVSTATIC_INIT);
192        boolean doesAlloc = (which == LF_NEWINVSPECIAL);
193        String linkerName;
194        LambdaForm.Kind kind;
195        switch (which) {
196        case LF_INVVIRTUAL:    linkerName = "linkToVirtual";   kind = DIRECT_INVOKE_VIRTUAL;     break;
197        case LF_INVSTATIC:     linkerName = "linkToStatic";    kind = DIRECT_INVOKE_STATIC;      break;
198        case LF_INVSTATIC_INIT:linkerName = "linkToStatic";    kind = DIRECT_INVOKE_STATIC_INIT; break;
199        case LF_INVSPECIAL:    linkerName = "linkToSpecial";   kind = DIRECT_INVOKE_SPECIAL;     break;
200        case LF_INVINTERFACE:  linkerName = "linkToInterface"; kind = DIRECT_INVOKE_INTERFACE;   break;
201        case LF_NEWINVSPECIAL: linkerName = "linkToSpecial";   kind = DIRECT_NEW_INVOKE_SPECIAL; break;
202        default:  throw new InternalError("which="+which);
203        }
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(getFunction(NF_allocateInstance), names[DMH_THIS]);
228            names[GET_MEMBER] = new Name(getFunction(NF_constructorMethod), names[DMH_THIS]);
229        } else if (needsInit) {
230            names[GET_MEMBER] = new Name(getFunction(NF_internalMemberNameEnsureInit), names[DMH_THIS]);
231        } else {
232            names[GET_MEMBER] = new Name(getFunction(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        LambdaForm lform = new LambdaForm(ARG_LIMIT, names, result, kind);
246
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    /* assert */ static Object findDirectMethodHandle(Name name) {
253        if (name.function.equals(getFunction(NF_internalMemberName)) ||
254            name.function.equals(getFunction(NF_internalMemberNameEnsureInit)) ||
255            name.function.equals(getFunction(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 (lform.vmentry == null && 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    static final 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    static final int
505            FT_LAST_WRAPPER    = Wrapper.COUNT-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    @Stable
515    private static final LambdaForm[] ACCESSOR_FORMS
516            = new LambdaForm[afIndex(AF_LIMIT, false, 0)];
517    static int ftypeKind(Class<?> ftype) {
518        if (ftype.isPrimitive())
519            return Wrapper.forPrimitiveType(ftype).ordinal();
520        else if (VerifyType.isNullReferenceConversion(Object.class, ftype))
521            return FT_UNCHECKED_REF;
522        else
523            return FT_CHECKED_REF;
524    }
525
526    /**
527     * Create a LF which can access the given field.
528     * Cache and share this structure among all fields with
529     * the same basicType and refKind.
530     */
531    private static LambdaForm preparedFieldLambdaForm(MemberName m) {
532        Class<?> ftype = m.getFieldType();
533        boolean isVolatile = m.isVolatile();
534        byte formOp;
535        switch (m.getReferenceKind()) {
536        case REF_getField:      formOp = AF_GETFIELD;    break;
537        case REF_putField:      formOp = AF_PUTFIELD;    break;
538        case REF_getStatic:     formOp = AF_GETSTATIC;   break;
539        case REF_putStatic:     formOp = AF_PUTSTATIC;   break;
540        default:  throw new InternalError(m.toString());
541        }
542        if (shouldBeInitialized(m)) {
543            // precompute the barrier-free version:
544            preparedFieldLambdaForm(formOp, isVolatile, ftype);
545            assert((AF_GETSTATIC_INIT - AF_GETSTATIC) ==
546                   (AF_PUTSTATIC_INIT - AF_PUTSTATIC));
547            formOp += (AF_GETSTATIC_INIT - AF_GETSTATIC);
548        }
549        LambdaForm lform = preparedFieldLambdaForm(formOp, isVolatile, ftype);
550        maybeCompile(lform, m);
551        assert(lform.methodType().dropParameterTypes(0, 1)
552                .equals(m.getInvocationType().basicType()))
553                : Arrays.asList(m, m.getInvocationType().basicType(), lform, lform.methodType());
554        return lform;
555    }
556    private static LambdaForm preparedFieldLambdaForm(byte formOp, boolean isVolatile, Class<?> ftype) {
557        int ftypeKind = ftypeKind(ftype);
558        int afIndex = afIndex(formOp, isVolatile, ftypeKind);
559        LambdaForm lform = ACCESSOR_FORMS[afIndex];
560        if (lform != null)  return lform;
561        lform = makePreparedFieldLambdaForm(formOp, isVolatile, ftypeKind);
562        ACCESSOR_FORMS[afIndex] = lform;  // don't bother with a CAS
563        return lform;
564    }
565
566    private static final Wrapper[] ALL_WRAPPERS = Wrapper.values();
567
568    private static Kind getFieldKind(boolean isGetter, boolean isVolatile, Wrapper wrapper) {
569        if (isGetter) {
570            if (isVolatile) {
571                switch (wrapper) {
572                    case BOOLEAN: return GET_BOOLEAN_VOLATILE;
573                    case BYTE:    return GET_BYTE_VOLATILE;
574                    case SHORT:   return GET_SHORT_VOLATILE;
575                    case CHAR:    return GET_CHAR_VOLATILE;
576                    case INT:     return GET_INT_VOLATILE;
577                    case LONG:    return GET_LONG_VOLATILE;
578                    case FLOAT:   return GET_FLOAT_VOLATILE;
579                    case DOUBLE:  return GET_DOUBLE_VOLATILE;
580                    case OBJECT:  return GET_OBJECT_VOLATILE;
581                }
582            } else {
583                switch (wrapper) {
584                    case BOOLEAN: return GET_BOOLEAN;
585                    case BYTE:    return GET_BYTE;
586                    case SHORT:   return GET_SHORT;
587                    case CHAR:    return GET_CHAR;
588                    case INT:     return GET_INT;
589                    case LONG:    return GET_LONG;
590                    case FLOAT:   return GET_FLOAT;
591                    case DOUBLE:  return GET_DOUBLE;
592                    case OBJECT:  return GET_OBJECT;
593                }
594            }
595        } else {
596            if (isVolatile) {
597                switch (wrapper) {
598                    case BOOLEAN: return PUT_BOOLEAN_VOLATILE;
599                    case BYTE:    return PUT_BYTE_VOLATILE;
600                    case SHORT:   return PUT_SHORT_VOLATILE;
601                    case CHAR:    return PUT_CHAR_VOLATILE;
602                    case INT:     return PUT_INT_VOLATILE;
603                    case LONG:    return PUT_LONG_VOLATILE;
604                    case FLOAT:   return PUT_FLOAT_VOLATILE;
605                    case DOUBLE:  return PUT_DOUBLE_VOLATILE;
606                    case OBJECT:  return PUT_OBJECT_VOLATILE;
607                }
608            } else {
609                switch (wrapper) {
610                    case BOOLEAN: return PUT_BOOLEAN;
611                    case BYTE:    return PUT_BYTE;
612                    case SHORT:   return PUT_SHORT;
613                    case CHAR:    return PUT_CHAR;
614                    case INT:     return PUT_INT;
615                    case LONG:    return PUT_LONG;
616                    case FLOAT:   return PUT_FLOAT;
617                    case DOUBLE:  return PUT_DOUBLE;
618                    case OBJECT:  return PUT_OBJECT;
619                }
620            }
621        }
622        throw new AssertionError("Invalid arguments");
623    }
624
625    static LambdaForm makePreparedFieldLambdaForm(byte formOp, boolean isVolatile, int ftypeKind) {
626        boolean isGetter  = (formOp & 1) == (AF_GETFIELD & 1);
627        boolean isStatic  = (formOp >= AF_GETSTATIC);
628        boolean needsInit = (formOp >= AF_GETSTATIC_INIT);
629        boolean needsCast = (ftypeKind == FT_CHECKED_REF);
630        Wrapper fw = (needsCast ? Wrapper.OBJECT : ALL_WRAPPERS[ftypeKind]);
631        Class<?> ft = fw.primitiveType();
632        assert(ftypeKind(needsCast ? String.class : ft) == ftypeKind);
633
634        // getObject, putIntVolatile, etc.
635        Kind kind = getFieldKind(isGetter, isVolatile, fw);
636
637        MethodType linkerType;
638        if (isGetter)
639            linkerType = MethodType.methodType(ft, Object.class, long.class);
640        else
641            linkerType = MethodType.methodType(void.class, Object.class, long.class, ft);
642        MemberName linker = new MemberName(Unsafe.class, kind.methodName, linkerType, REF_invokeVirtual);
643        try {
644            linker = IMPL_NAMES.resolveOrFail(REF_invokeVirtual, linker, null, NoSuchMethodException.class);
645        } catch (ReflectiveOperationException ex) {
646            throw newInternalError(ex);
647        }
648
649        // What is the external type of the lambda form?
650        MethodType mtype;
651        if (isGetter)
652            mtype = MethodType.methodType(ft);
653        else
654            mtype = MethodType.methodType(void.class, ft);
655        mtype = mtype.basicType();  // erase short to int, etc.
656        if (!isStatic)
657            mtype = mtype.insertParameterTypes(0, Object.class);
658        final int DMH_THIS  = 0;
659        final int ARG_BASE  = 1;
660        final int ARG_LIMIT = ARG_BASE + mtype.parameterCount();
661        // if this is for non-static access, the base pointer is stored at this index:
662        final int OBJ_BASE  = isStatic ? -1 : ARG_BASE;
663        // if this is for write access, the value to be written is stored at this index:
664        final int SET_VALUE  = isGetter ? -1 : ARG_LIMIT - 1;
665        int nameCursor = ARG_LIMIT;
666        final int F_HOLDER  = (isStatic ? nameCursor++ : -1);  // static base if any
667        final int F_OFFSET  = nameCursor++;  // Either static offset or field offset.
668        final int OBJ_CHECK = (OBJ_BASE >= 0 ? nameCursor++ : -1);
669        final int U_HOLDER  = nameCursor++;  // UNSAFE holder
670        final int INIT_BAR  = (needsInit ? nameCursor++ : -1);
671        final int PRE_CAST  = (needsCast && !isGetter ? nameCursor++ : -1);
672        final int LINKER_CALL = nameCursor++;
673        final int POST_CAST = (needsCast && isGetter ? nameCursor++ : -1);
674        final int RESULT    = nameCursor-1;  // either the call or the cast
675        Name[] names = arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
676        if (needsInit)
677            names[INIT_BAR] = new Name(getFunction(NF_ensureInitialized), names[DMH_THIS]);
678        if (needsCast && !isGetter)
679            names[PRE_CAST] = new Name(getFunction(NF_checkCast), names[DMH_THIS], names[SET_VALUE]);
680        Object[] outArgs = new Object[1 + linkerType.parameterCount()];
681        assert(outArgs.length == (isGetter ? 3 : 4));
682        outArgs[0] = names[U_HOLDER] = new Name(getFunction(NF_UNSAFE));
683        if (isStatic) {
684            outArgs[1] = names[F_HOLDER]  = new Name(getFunction(NF_staticBase), names[DMH_THIS]);
685            outArgs[2] = names[F_OFFSET]  = new Name(getFunction(NF_staticOffset), names[DMH_THIS]);
686        } else {
687            outArgs[1] = names[OBJ_CHECK] = new Name(getFunction(NF_checkBase), names[OBJ_BASE]);
688            outArgs[2] = names[F_OFFSET]  = new Name(getFunction(NF_fieldOffset), names[DMH_THIS]);
689        }
690        if (!isGetter) {
691            outArgs[3] = (needsCast ? names[PRE_CAST] : names[SET_VALUE]);
692        }
693        for (Object a : outArgs)  assert(a != null);
694        names[LINKER_CALL] = new Name(linker, outArgs);
695        if (needsCast && isGetter)
696            names[POST_CAST] = new Name(getFunction(NF_checkCast), names[DMH_THIS], names[LINKER_CALL]);
697        for (Name n : names)  assert(n != null);
698
699        LambdaForm form;
700        if (needsCast || needsInit) {
701            // can't use the pre-generated form when casting and/or initializing
702            form = new LambdaForm(ARG_LIMIT, names, RESULT);
703        } else {
704            form = new LambdaForm(ARG_LIMIT, names, RESULT, kind);
705        }
706
707        if (LambdaForm.debugNames()) {
708            // add some detail to the lambdaForm debugname,
709            // significant only for debugging
710            StringBuilder nameBuilder = new StringBuilder(kind.methodName);
711            if (isStatic) {
712                nameBuilder.append("Static");
713            } else {
714                nameBuilder.append("Field");
715            }
716            if (needsCast) {
717                nameBuilder.append("Cast");
718            }
719            if (needsInit) {
720                nameBuilder.append("Init");
721            }
722            LambdaForm.associateWithDebugName(form, nameBuilder.toString());
723        }
724        return form;
725    }
726
727    /**
728     * Pre-initialized NamedFunctions for bootstrapping purposes.
729     */
730    static final byte NF_internalMemberName = 0,
731            NF_internalMemberNameEnsureInit = 1,
732            NF_ensureInitialized = 2,
733            NF_fieldOffset = 3,
734            NF_checkBase = 4,
735            NF_staticBase = 5,
736            NF_staticOffset = 6,
737            NF_checkCast = 7,
738            NF_allocateInstance = 8,
739            NF_constructorMethod = 9,
740            NF_UNSAFE = 10,
741            NF_LIMIT = 11;
742
743    private static final @Stable NamedFunction[] NFS = new NamedFunction[NF_LIMIT];
744
745    private static NamedFunction getFunction(byte func) {
746        NamedFunction nf = NFS[func];
747        if (nf != null) {
748            return nf;
749        }
750        // Each nf must be statically invocable or we get tied up in our bootstraps.
751        nf = NFS[func] = createFunction(func);
752        assert(InvokerBytecodeGenerator.isStaticallyInvocable(nf));
753        return nf;
754    }
755
756    private static NamedFunction createFunction(byte func) {
757        try {
758            switch (func) {
759                case NF_internalMemberName:
760                    return new NamedFunction(DirectMethodHandle.class
761                            .getDeclaredMethod("internalMemberName", Object.class));
762                case NF_internalMemberNameEnsureInit:
763                    return new NamedFunction(DirectMethodHandle.class
764                            .getDeclaredMethod("internalMemberNameEnsureInit", Object.class));
765                case NF_ensureInitialized:
766                    return new NamedFunction(DirectMethodHandle.class
767                            .getDeclaredMethod("ensureInitialized", Object.class));
768                case NF_fieldOffset:
769                    return new NamedFunction(DirectMethodHandle.class
770                            .getDeclaredMethod("fieldOffset", Object.class));
771                case NF_checkBase:
772                    return new NamedFunction(DirectMethodHandle.class
773                            .getDeclaredMethod("checkBase", Object.class));
774                case NF_staticBase:
775                    return new NamedFunction(DirectMethodHandle.class
776                            .getDeclaredMethod("staticBase", Object.class));
777                case NF_staticOffset:
778                    return new NamedFunction(DirectMethodHandle.class
779                            .getDeclaredMethod("staticOffset", Object.class));
780                case NF_checkCast:
781                    return new NamedFunction(DirectMethodHandle.class
782                            .getDeclaredMethod("checkCast", Object.class, Object.class));
783                case NF_allocateInstance:
784                    return new NamedFunction(DirectMethodHandle.class
785                            .getDeclaredMethod("allocateInstance", Object.class));
786                case NF_constructorMethod:
787                    return new NamedFunction(DirectMethodHandle.class
788                            .getDeclaredMethod("constructorMethod", Object.class));
789                case NF_UNSAFE:
790                    return new NamedFunction(new MemberName(MethodHandleStatics.class
791                            .getDeclaredField("UNSAFE")));
792                default:
793                    throw newInternalError("Unknown function: " + func);
794            }
795        } catch (ReflectiveOperationException ex) {
796            throw newInternalError(ex);
797        }
798    }
799
800    static {
801        // The Holder class will contain pre-generated DirectMethodHandles resolved
802        // speculatively using MemberName.getFactory().resolveOrNull. However, that
803        // doesn't initialize the class, which subtly breaks inlining etc. By forcing
804        // initialization of the Holder class we avoid these issues.
805        UNSAFE.ensureClassInitialized(Holder.class);
806    }
807
808    /* Placeholder class for DirectMethodHandles generated ahead of time */
809    final class Holder {}
810}
811