1 /*
  2  * Copyright (c) 2008, 2025, 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 jdk.internal.misc.CDS;
 29 import jdk.internal.misc.Unsafe;
 30 import jdk.internal.vm.annotation.AOTSafeClassInitializer;
 31 import jdk.internal.vm.annotation.ForceInline;
 32 import jdk.internal.vm.annotation.Stable;
 33 import sun.invoke.util.ValueConversions;
 34 import sun.invoke.util.VerifyAccess;
 35 import sun.invoke.util.Wrapper;
 36 
 37 import java.util.Arrays;
 38 import java.util.Objects;
 39 import java.util.function.Function;
 40 
 41 import static java.lang.invoke.LambdaForm.*;
 42 import static java.lang.invoke.LambdaForm.Kind.*;
 43 import static java.lang.invoke.MethodHandleNatives.Constants.*;
 44 import static java.lang.invoke.MethodHandleStatics.UNSAFE;
 45 import static java.lang.invoke.MethodHandleStatics.newInternalError;
 46 import static java.lang.invoke.MethodTypeForm.*;
 47 
 48 /**
 49  * The flavor of method handle which implements a constant reference
 50  * to a class member.
 51  * @author jrose
 52  */
 53 @AOTSafeClassInitializer
 54 sealed class DirectMethodHandle extends MethodHandle {
 55     final MemberName member;
 56     final boolean crackable;
 57 
 58     // Constructors and factory methods in this class *must* be package scoped or private.
 59     private DirectMethodHandle(MethodType mtype, LambdaForm form, MemberName member, boolean crackable) {
 60         super(mtype, form);
 61         if (!member.isResolved())  throw new InternalError();
 62 
 63         if (member.getDeclaringClass().isInterface() &&
 64             member.getReferenceKind() == REF_invokeInterface &&
 65             member.isMethod() && !member.isAbstract()) {
 66             // Check for corner case: invokeinterface of Object method
 67             MemberName m = new MemberName(Object.class, member.getName(), member.getMethodType(), member.getReferenceKind());
 68             m = MemberName.getFactory().resolveOrNull(m.getReferenceKind(), m, null, LM_TRUSTED);
 69             if (m != null && m.isPublic()) {
 70                 assert(member.getReferenceKind() == m.getReferenceKind());  // else this.form is wrong
 71                 member = m;
 72             }
 73         }
 74 
 75         this.member = member;
 76         this.crackable = crackable;
 77     }
 78 
 79     // Factory methods:
 80     static DirectMethodHandle make(byte refKind, Class<?> refc, MemberName member, Class<?> callerClass) {
 81         MethodType mtype = member.getMethodOrFieldType();
 82         if (!member.isStatic()) {
 83             if (!member.getDeclaringClass().isAssignableFrom(refc) || member.isConstructor())
 84                 throw new InternalError(member.toString());
 85             mtype = mtype.insertParameterTypes(0, refc);
 86         }
 87         if (!member.isField()) {
 88             // refKind reflects the original type of lookup via findSpecial or
 89             // findVirtual etc.
 90             return switch (refKind) {
 91                 case REF_invokeSpecial -> {
 92                     member = member.asSpecial();
 93                     // if caller is an interface we need to adapt to get the
 94                     // receiver check inserted
 95                     if (callerClass == null) {
 96                         throw new InternalError("callerClass must not be null for REF_invokeSpecial");
 97                     }
 98                     LambdaForm lform = preparedLambdaForm(member, callerClass.isInterface());
 99                     yield new Special(mtype, lform, member, true, callerClass);
100                 }
101                 case REF_invokeInterface -> {
102                     // for interfaces we always need the receiver typecheck,
103                     // so we always pass 'true' to ensure we adapt if needed
104                     // to include the REF_invokeSpecial case
105                     LambdaForm lform = preparedLambdaForm(member, true);
106                     yield new Interface(mtype, lform, member, true, refc);
107                 }
108                 default -> {
109                     LambdaForm lform = preparedLambdaForm(member);
110                     yield new DirectMethodHandle(mtype, lform, member, true);
111                 }
112             };
113         } else {
114             LambdaForm lform = preparedFieldLambdaForm(member);
115             if (member.isStatic()) {
116                 long offset = MethodHandleNatives.staticFieldOffset(member);
117                 Object base = MethodHandleNatives.staticFieldBase(member);
118                 return new StaticAccessor(mtype, lform, member, true, base, offset);
119             } else {
120                 long offset = MethodHandleNatives.objectFieldOffset(member);
121                 assert(offset == (int)offset);
122                 return new Accessor(mtype, lform, member, true, (int)offset);
123             }
124         }
125     }
126     static DirectMethodHandle make(Class<?> refc, MemberName member) {
127         byte refKind = member.getReferenceKind();
128         if (refKind == REF_invokeSpecial)
129             refKind =  REF_invokeVirtual;
130         return make(refKind, refc, member, null /* no callerClass context */);
131     }
132     static DirectMethodHandle make(MemberName member) {
133         if (member.isConstructor())
134             return makeAllocator(member.getDeclaringClass(), member);
135         return make(member.getDeclaringClass(), member);
136     }
137     static DirectMethodHandle makeAllocator(Class<?> instanceClass, MemberName ctor) {
138         assert(ctor.isConstructor() && ctor.getName().equals("<init>"));
139         ctor = ctor.asConstructor();
140         assert(ctor.isConstructor() && ctor.getReferenceKind() == REF_newInvokeSpecial) : ctor;
141         MethodType mtype = ctor.getMethodType().changeReturnType(instanceClass);
142         LambdaForm lform = preparedLambdaForm(ctor);
143         MemberName init = ctor.asSpecial();
144         assert(init.getMethodType().returnType() == void.class);
145         return new Constructor(mtype, lform, ctor, true, init, instanceClass);
146     }
147 
148     @Override
149     BoundMethodHandle rebind() {
150         return BoundMethodHandle.makeReinvoker(this);
151     }
152 
153     @Override
154     MethodHandle copyWith(MethodType mt, LambdaForm lf) {
155         assert(this.getClass() == DirectMethodHandle.class);  // must override in subclasses
156         return new DirectMethodHandle(mt, lf, member, crackable);
157     }
158 
159     @Override
160     MethodHandle viewAsType(MethodType newType, boolean strict) {
161         // No actual conversions, just a new view of the same method.
162         // However, we must not expose a DMH that is crackable into a
163         // MethodHandleInfo, so we return a cloned, uncrackable DMH
164         assert(viewAsTypeChecks(newType, strict));
165         assert(this.getClass() == DirectMethodHandle.class);  // must override in subclasses
166         return new DirectMethodHandle(newType, form, member, false);
167     }
168 
169     @Override
170     boolean isCrackable() {
171         return crackable;
172     }
173 
174     @Override
175     String internalProperties(int indentLevel) {
176         return "\n" + debugPrefix(indentLevel) + "& DMH.MN=" + internalMemberName();
177     }
178 
179     //// Implementation methods.
180     @Override
181     @ForceInline
182     MemberName internalMemberName() {
183         return member;
184     }
185 
186     private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory();
187 
188     /**
189      * Create a LF which can invoke the given method.
190      * Cache and share this structure among all methods with
191      * the same basicType and refKind.
192      */
193     private static LambdaForm preparedLambdaForm(MemberName m, boolean adaptToSpecialIfc) {
194         assert(m.isInvocable()) : m;  // call preparedFieldLambdaForm instead
195         MethodType mtype = m.getInvocationType().basicType();
196         assert(!m.isMethodHandleInvoke()) : m;
197         // MemberName.getReferenceKind represents the JVM optimized form of the call
198         // as distinct from the "kind" passed to DMH.make which represents the original
199         // bytecode-equivalent request. Specifically private/final methods that use a direct
200         // call have getReferenceKind adapted to REF_invokeSpecial, even though the actual
201         // invocation mode may be invokevirtual or invokeinterface.
202         int which = switch (m.getReferenceKind()) {
203             case REF_invokeVirtual    -> LF_INVVIRTUAL;
204             case REF_invokeStatic     -> LF_INVSTATIC;
205             case REF_invokeSpecial    -> LF_INVSPECIAL;
206             case REF_invokeInterface  -> LF_INVINTERFACE;
207             case REF_newInvokeSpecial -> LF_NEWINVSPECIAL;
208             default -> throw new InternalError(m.toString());
209         };
210         if (which == LF_INVSTATIC && shouldBeInitialized(m)) {
211             // precompute the barrier-free version:
212             preparedLambdaForm(mtype, which);
213             which = LF_INVSTATIC_INIT;
214         }
215         if (which == LF_INVSPECIAL && adaptToSpecialIfc) {
216             which = LF_INVSPECIAL_IFC;
217         }
218         LambdaForm lform = preparedLambdaForm(mtype, which);
219         assert(lform.methodType().dropParameterTypes(0, 1)
220                 .equals(m.getInvocationType().basicType()))
221                 : Arrays.asList(m, m.getInvocationType().basicType(), lform, lform.methodType());
222         return lform;
223     }
224 
225     private static LambdaForm preparedLambdaForm(MemberName m) {
226         return preparedLambdaForm(m, false);
227     }
228 
229     private static LambdaForm preparedLambdaForm(MethodType mtype, int which) {
230         LambdaForm lform = mtype.form().cachedLambdaForm(which);
231         if (lform != null)  return lform;
232         lform = makePreparedLambdaForm(mtype, which);
233         return mtype.form().setCachedLambdaForm(which, lform);
234     }
235 
236     static LambdaForm makePreparedLambdaForm(MethodType mtype, int which) {
237         boolean needsInit = (which == LF_INVSTATIC_INIT);
238         boolean doesAlloc = (which == LF_NEWINVSPECIAL);
239         boolean needsReceiverCheck = (which == LF_INVINTERFACE ||
240                                       which == LF_INVSPECIAL_IFC);
241 
242         String linkerName;
243         LambdaForm.Kind kind;
244         switch (which) {
245         case LF_INVVIRTUAL:    linkerName = "linkToVirtual";   kind = DIRECT_INVOKE_VIRTUAL;     break;
246         case LF_INVSTATIC:     linkerName = "linkToStatic";    kind = DIRECT_INVOKE_STATIC;      break;
247         case LF_INVSTATIC_INIT:linkerName = "linkToStatic";    kind = DIRECT_INVOKE_STATIC_INIT; break;
248         case LF_INVSPECIAL_IFC:linkerName = "linkToSpecial";   kind = DIRECT_INVOKE_SPECIAL_IFC; break;
249         case LF_INVSPECIAL:    linkerName = "linkToSpecial";   kind = DIRECT_INVOKE_SPECIAL;     break;
250         case LF_INVINTERFACE:  linkerName = "linkToInterface"; kind = DIRECT_INVOKE_INTERFACE;   break;
251         case LF_NEWINVSPECIAL: linkerName = "linkToSpecial";   kind = DIRECT_NEW_INVOKE_SPECIAL; break;
252         default:  throw new InternalError("which="+which);
253         }
254 
255         MethodType mtypeWithArg;
256         if (doesAlloc) {
257             var ptypes = mtype.ptypes();
258             var newPtypes = new Class<?>[ptypes.length + 2];
259             newPtypes[0] = Object.class; // insert newly allocated obj
260             System.arraycopy(ptypes, 0, newPtypes, 1, ptypes.length);
261             newPtypes[newPtypes.length - 1] = MemberName.class;
262             mtypeWithArg = MethodType.methodType(void.class, newPtypes, true);
263         } else {
264             mtypeWithArg = mtype.appendParameterTypes(MemberName.class);
265         }
266         MemberName linker = new MemberName(MethodHandle.class, linkerName, mtypeWithArg, REF_invokeStatic);
267         try {
268             linker = IMPL_NAMES.resolveOrFail(REF_invokeStatic, linker, null, LM_TRUSTED,
269                                               NoSuchMethodException.class);
270         } catch (ReflectiveOperationException ex) {
271             throw newInternalError(ex);
272         }
273         final int DMH_THIS    = 0;
274         final int ARG_BASE    = 1;
275         final int ARG_LIMIT   = ARG_BASE + mtype.parameterCount();
276         int nameCursor = ARG_LIMIT;
277         final int NEW_OBJ     = (doesAlloc ? nameCursor++ : -1);
278         final int GET_MEMBER  = nameCursor++;
279         final int CHECK_RECEIVER = (needsReceiverCheck ? nameCursor++ : -1);
280         final int LINKER_CALL = nameCursor++;
281         Name[] names = invokeArguments(nameCursor - ARG_LIMIT, mtype);
282         assert(names.length == nameCursor);
283         if (doesAlloc) {
284             // names = { argx,y,z,... new C, init method }
285             names[NEW_OBJ] = new Name(getFunction(NF_allocateInstance), names[DMH_THIS]);
286             names[GET_MEMBER] = new Name(getFunction(NF_constructorMethod), names[DMH_THIS]);
287         } else if (needsInit) {
288             names[GET_MEMBER] = new Name(getFunction(NF_internalMemberNameEnsureInit), names[DMH_THIS]);
289         } else {
290             names[GET_MEMBER] = new Name(getFunction(NF_internalMemberName), names[DMH_THIS]);
291         }
292         assert(findDirectMethodHandle(names[GET_MEMBER]) == names[DMH_THIS]);
293         Object[] outArgs = Arrays.copyOfRange(names, ARG_BASE, GET_MEMBER+1, Object[].class);
294         if (needsReceiverCheck) {
295             names[CHECK_RECEIVER] = new Name(getFunction(NF_checkReceiver), names[DMH_THIS], names[ARG_BASE]);
296             outArgs[0] = names[CHECK_RECEIVER];
297         }
298         assert(outArgs[outArgs.length-1] == names[GET_MEMBER]);  // look, shifted args!
299         int result = LAST_RESULT;
300         if (doesAlloc) {
301             assert(outArgs[outArgs.length-2] == names[NEW_OBJ]);  // got to move this one
302             System.arraycopy(outArgs, 0, outArgs, 1, outArgs.length-2);
303             outArgs[0] = names[NEW_OBJ];
304             result = NEW_OBJ;
305         }
306         names[LINKER_CALL] = new Name(linker, outArgs);
307         LambdaForm lform = LambdaForm.create(ARG_LIMIT, names, result, kind);
308 
309         // This is a tricky bit of code.  Don't send it through the LF interpreter.
310         lform.compileToBytecode();
311         return lform;
312     }
313 
314     /* assert */ static Object findDirectMethodHandle(Name name) {
315         if (name.function.equals(getFunction(NF_internalMemberName)) ||
316             name.function.equals(getFunction(NF_internalMemberNameEnsureInit)) ||
317             name.function.equals(getFunction(NF_constructorMethod))) {
318             assert(name.arguments.length == 1);
319             return name.arguments[0];
320         }
321         return null;
322     }
323 
324     /** Static wrapper for DirectMethodHandle.internalMemberName. */
325     @ForceInline
326     /*non-public*/
327     static Object internalMemberName(Object mh) {
328         return ((DirectMethodHandle)mh).member;
329     }
330 
331     /** Static wrapper for DirectMethodHandle.internalMemberName.
332      * This one also forces initialization.
333      */
334     /*non-public*/
335     static Object internalMemberNameEnsureInit(Object mh) {
336         DirectMethodHandle dmh = (DirectMethodHandle)mh;
337         dmh.ensureInitialized();
338         return dmh.member;
339     }
340 
341     /*non-public*/
342     static boolean shouldBeInitialized(MemberName member) {
343         switch (member.getReferenceKind()) {
344         case REF_invokeStatic:
345         case REF_getStatic:
346         case REF_putStatic:
347         case REF_newInvokeSpecial:
348             break;
349         default:
350             // No need to initialize the class on this kind of member.
351             return false;
352         }
353         Class<?> cls = member.getDeclaringClass();
354         if (cls == ValueConversions.class ||
355             cls == MethodHandleImpl.class ||
356             cls == Invokers.class) {
357             // These guys have lots of <clinit> DMH creation but we know
358             // the MHs will not be used until the system is booted.
359             return false;
360         }
361         if (VerifyAccess.isSamePackage(MethodHandle.class, cls) ||
362             VerifyAccess.isSamePackage(ValueConversions.class, cls)) {
363             // It is a system class.  It is probably in the process of
364             // being initialized, but we will help it along just to be safe.
365             UNSAFE.ensureClassInitialized(cls);
366             return CDS.needsClassInitBarrier(cls);
367         }
368         return UNSAFE.shouldBeInitialized(cls) || CDS.needsClassInitBarrier(cls);
369     }
370 
371     private void ensureInitialized() {
372         if (checkInitialized(member)) {
373             // The coast is clear.  Delete the <clinit> barrier.
374             updateForm(new Function<>() {
375                 public LambdaForm apply(LambdaForm oldForm) {
376                     return (member.isField() ? preparedFieldLambdaForm(member)
377                                              : preparedLambdaForm(member));
378                 }
379             });
380         }
381     }
382     private static boolean checkInitialized(MemberName member) {
383         Class<?> defc = member.getDeclaringClass();
384         UNSAFE.ensureClassInitialized(defc);
385         // Once we get here either defc was fully initialized by another thread, or
386         // defc was already being initialized by the current thread. In the latter case
387         // the barrier must remain. We can detect this simply by checking if initialization
388         // is still needed.
389         return !UNSAFE.shouldBeInitialized(defc);
390     }
391 
392     /*non-public*/
393     static void ensureInitialized(Object mh) {
394         ((DirectMethodHandle)mh).ensureInitialized();
395     }
396 
397     /** This subclass represents invokespecial instructions. */
398     static final class Special extends DirectMethodHandle {
399         private final Class<?> caller;
400         private Special(MethodType mtype, LambdaForm form, MemberName member, boolean crackable, Class<?> caller) {
401             super(mtype, form, member, crackable);
402             this.caller = caller;
403         }
404         @Override
405         boolean isInvokeSpecial() {
406             return true;
407         }
408         @Override
409         MethodHandle copyWith(MethodType mt, LambdaForm lf) {
410             return new Special(mt, lf, member, crackable, caller);
411         }
412         @Override
413         MethodHandle viewAsType(MethodType newType, boolean strict) {
414             assert(viewAsTypeChecks(newType, strict));
415             return new Special(newType, form, member, false, caller);
416         }
417         Object checkReceiver(Object recv) {
418             if (!caller.isInstance(recv)) {
419                 if (recv != null) {
420                     String msg = String.format("Receiver class %s is not a subclass of caller class %s",
421                                                recv.getClass().getName(), caller.getName());
422                     throw new IncompatibleClassChangeError(msg);
423                 } else {
424                     String msg = String.format("Cannot invoke %s with null receiver", member);
425                     throw new NullPointerException(msg);
426                 }
427             }
428             return recv;
429         }
430     }
431 
432     /** This subclass represents invokeinterface instructions. */
433     static final class Interface extends DirectMethodHandle {
434         private final Class<?> refc;
435         private Interface(MethodType mtype, LambdaForm form, MemberName member, boolean crackable, Class<?> refc) {
436             super(mtype, form, member, crackable);
437             assert(refc.isInterface()) : refc;
438             this.refc = refc;
439         }
440         @Override
441         MethodHandle copyWith(MethodType mt, LambdaForm lf) {
442             return new Interface(mt, lf, member, crackable, refc);
443         }
444         @Override
445         MethodHandle viewAsType(MethodType newType, boolean strict) {
446             assert(viewAsTypeChecks(newType, strict));
447             return new Interface(newType, form, member, false, refc);
448         }
449         @Override
450         Object checkReceiver(Object recv) {
451             if (!refc.isInstance(recv)) {
452                 if (recv != null) {
453                     String msg = String.format("Receiver class %s does not implement the requested interface %s",
454                                                recv.getClass().getName(), refc.getName());
455                     throw new IncompatibleClassChangeError(msg);
456                 } else {
457                     String msg = String.format("Cannot invoke %s with null receiver", member);
458                     throw new NullPointerException(msg);
459                 }
460             }
461             return recv;
462         }
463     }
464 
465     /** Used for interface receiver type checks, by Interface and Special modes. */
466     Object checkReceiver(Object recv) {
467         throw new InternalError("Should only be invoked on a subclass");
468     }
469 
470     /** This subclass handles constructor references. */
471     @AOTSafeClassInitializer
472     static final class Constructor extends DirectMethodHandle {
473         final MemberName initMethod;
474         final Class<?>   instanceClass;
475 
476         private Constructor(MethodType mtype, LambdaForm form, MemberName constructor,
477                             boolean crackable, MemberName initMethod, Class<?> instanceClass) {
478             super(mtype, form, constructor, crackable);
479             this.initMethod = initMethod;
480             this.instanceClass = instanceClass;
481             assert(initMethod.isResolved());
482         }
483         @Override
484         MethodHandle copyWith(MethodType mt, LambdaForm lf) {
485             return new Constructor(mt, lf, member, crackable, initMethod, instanceClass);
486         }
487         @Override
488         MethodHandle viewAsType(MethodType newType, boolean strict) {
489             assert(viewAsTypeChecks(newType, strict));
490             return new Constructor(newType, form, member, false, initMethod, instanceClass);
491         }
492     }
493 
494     /*non-public*/
495     static Object constructorMethod(Object mh) {
496         Constructor dmh = (Constructor)mh;
497         return dmh.initMethod;
498     }
499 
500     /*non-public*/
501     static Object allocateInstance(Object mh) throws InstantiationException {
502         Constructor dmh = (Constructor)mh;
503         return UNSAFE.allocateInstance(dmh.instanceClass);
504     }
505 
506     /** This subclass handles non-static field references. */
507     static final class Accessor extends DirectMethodHandle {
508         final Class<?> fieldType;
509         final int      fieldOffset;
510         private Accessor(MethodType mtype, LambdaForm form, MemberName member,
511                          boolean crackable, int fieldOffset) {
512             super(mtype, form, member, crackable);
513             this.fieldType   = member.getFieldType();
514             this.fieldOffset = fieldOffset;
515         }
516 
517         @Override Object checkCast(Object obj) {
518             return fieldType.cast(obj);
519         }
520         @Override
521         MethodHandle copyWith(MethodType mt, LambdaForm lf) {
522             return new Accessor(mt, lf, member, crackable, fieldOffset);
523         }
524         @Override
525         MethodHandle viewAsType(MethodType newType, boolean strict) {
526             assert(viewAsTypeChecks(newType, strict));
527             return new Accessor(newType, form, member, false, fieldOffset);
528         }
529     }
530 
531     @ForceInline
532     /*non-public*/
533     static long fieldOffset(Object accessorObj) {
534         // Note: We return a long because that is what Unsafe.getObject likes.
535         // We store a plain int because it is more compact.
536         return ((Accessor)accessorObj).fieldOffset;
537     }
538 
539     @ForceInline
540     /*non-public*/
541     static Object checkBase(Object obj) {
542         // Note that the object's class has already been verified,
543         // since the parameter type of the Accessor method handle
544         // is either member.getDeclaringClass or a subclass.
545         // This was verified in DirectMethodHandle.make.
546         // Therefore, the only remaining check is for null.
547         // Since this check is *not* guaranteed by Unsafe.getInt
548         // and its siblings, we need to make an explicit one here.
549         return Objects.requireNonNull(obj);
550     }
551 
552     /** This subclass handles static field references. */
553     static final class StaticAccessor extends DirectMethodHandle {
554         private final Class<?> fieldType;
555         private final Object   staticBase;
556         private final long     staticOffset;
557 
558         private StaticAccessor(MethodType mtype, LambdaForm form, MemberName member,
559                                boolean crackable, Object staticBase, long staticOffset) {
560             super(mtype, form, member, crackable);
561             this.fieldType    = member.getFieldType();
562             this.staticBase   = staticBase;
563             this.staticOffset = staticOffset;
564         }
565 
566         @Override Object checkCast(Object obj) {
567             return fieldType.cast(obj);
568         }
569         @Override
570         MethodHandle copyWith(MethodType mt, LambdaForm lf) {
571             return new StaticAccessor(mt, lf, member, crackable, staticBase, staticOffset);
572         }
573         @Override
574         MethodHandle viewAsType(MethodType newType, boolean strict) {
575             assert(viewAsTypeChecks(newType, strict));
576             return new StaticAccessor(newType, form, member, false, staticBase, staticOffset);
577         }
578     }
579 
580     @ForceInline
581     /*non-public*/
582     static Object nullCheck(Object obj) {
583         return Objects.requireNonNull(obj);
584     }
585 
586     @ForceInline
587     /*non-public*/
588     static Object staticBase(Object accessorObj) {
589         return ((StaticAccessor)accessorObj).staticBase;
590     }
591 
592     @ForceInline
593     /*non-public*/
594     static long staticOffset(Object accessorObj) {
595         return ((StaticAccessor)accessorObj).staticOffset;
596     }
597 
598     @ForceInline
599     /*non-public*/
600     static Object checkCast(Object mh, Object obj) {
601         return ((DirectMethodHandle) mh).checkCast(obj);
602     }
603 
604     Object checkCast(Object obj) {
605         return member.getMethodType().returnType().cast(obj);
606     }
607 
608     // Caching machinery for field accessors:
609     static final byte
610             AF_GETFIELD        = 0,
611             AF_PUTFIELD        = 1,
612             AF_GETSTATIC       = 2,
613             AF_PUTSTATIC       = 3,
614             AF_GETSTATIC_INIT  = 4,
615             AF_PUTSTATIC_INIT  = 5,
616             AF_LIMIT           = 6;
617     // Enumerate the different field kinds using Wrapper,
618     // with an extra case added for checked references.
619     static final int
620             FT_UNCHECKED_REF   = Wrapper.OBJECT.ordinal(),
621             FT_CHECKED_REF     = Wrapper.VOID.ordinal(),
622             FT_LIMIT           = Wrapper.COUNT;
623     private static int afIndex(byte formOp, boolean isVolatile, int ftypeKind) {
624         return ((formOp * FT_LIMIT * 2)
625                 + (isVolatile ? FT_LIMIT : 0)
626                 + ftypeKind);
627     }
628     @Stable
629     private static final LambdaForm[] ACCESSOR_FORMS
630             = new LambdaForm[afIndex(AF_LIMIT, false, 0)];
631     static int ftypeKind(Class<?> ftype) {
632         if (ftype.isPrimitive()) {
633             return Wrapper.forPrimitiveType(ftype).ordinal();
634         } else if (ftype.isInterface() || ftype.isAssignableFrom(Object.class)) {
635             // retyping can be done without a cast
636             return FT_UNCHECKED_REF;
637         } else {
638             return FT_CHECKED_REF;
639         }
640     }
641 
642     /**
643      * Create a LF which can access the given field.
644      * Cache and share this structure among all fields with
645      * the same basicType and refKind.
646      */
647     private static LambdaForm preparedFieldLambdaForm(MemberName m) {
648         Class<?> ftype = m.getFieldType();
649         boolean isVolatile = m.isVolatile();
650         byte formOp = switch (m.getReferenceKind()) {
651             case REF_getField  -> AF_GETFIELD;
652             case REF_putField  -> AF_PUTFIELD;
653             case REF_getStatic -> AF_GETSTATIC;
654             case REF_putStatic -> AF_PUTSTATIC;
655             default -> throw new InternalError(m.toString());
656         };
657         if (shouldBeInitialized(m)) {
658             // precompute the barrier-free version:
659             preparedFieldLambdaForm(formOp, isVolatile, ftype);
660             assert((AF_GETSTATIC_INIT - AF_GETSTATIC) ==
661                    (AF_PUTSTATIC_INIT - AF_PUTSTATIC));
662             formOp += (AF_GETSTATIC_INIT - AF_GETSTATIC);
663         }
664         LambdaForm lform = preparedFieldLambdaForm(formOp, isVolatile, ftype);
665         assert(lform.methodType().dropParameterTypes(0, 1)
666                 .equals(m.getInvocationType().basicType()))
667                 : Arrays.asList(m, m.getInvocationType().basicType(), lform, lform.methodType());
668         return lform;
669     }
670     private static LambdaForm preparedFieldLambdaForm(byte formOp, boolean isVolatile, Class<?> ftype) {
671         int ftypeKind = ftypeKind(ftype);
672         int afIndex = afIndex(formOp, isVolatile, ftypeKind);
673         LambdaForm lform = ACCESSOR_FORMS[afIndex];
674         if (lform != null)  return lform;
675         lform = makePreparedFieldLambdaForm(formOp, isVolatile, ftypeKind);
676         ACCESSOR_FORMS[afIndex] = lform;  // don't bother with a CAS
677         return lform;
678     }
679 
680     private static final @Stable Wrapper[] ALL_WRAPPERS = Wrapper.values();
681 
682     // Names in kind may overload but differ from their basic type
683     private static Kind getFieldKind(boolean isVolatile, boolean needsInit, boolean needsCast, Wrapper wrapper) {
684         if (isVolatile) {
685             if (needsInit) {
686                 return switch (wrapper) {
687                     case BYTE -> VOLATILE_FIELD_ACCESS_INIT_B;
688                     case CHAR -> VOLATILE_FIELD_ACCESS_INIT_C;
689                     case SHORT -> VOLATILE_FIELD_ACCESS_INIT_S;
690                     case BOOLEAN -> VOLATILE_FIELD_ACCESS_INIT_Z;
691                     default -> needsCast ? VOLATILE_FIELD_ACCESS_INIT_CAST : VOLATILE_FIELD_ACCESS_INIT;
692                 };
693             } else {
694                 return switch (wrapper) {
695                     case BYTE -> VOLATILE_FIELD_ACCESS_B;
696                     case CHAR -> VOLATILE_FIELD_ACCESS_C;
697                     case SHORT -> VOLATILE_FIELD_ACCESS_S;
698                     case BOOLEAN -> VOLATILE_FIELD_ACCESS_Z;
699                     default -> needsCast ? VOLATILE_FIELD_ACCESS_CAST : VOLATILE_FIELD_ACCESS;
700                 };
701             }
702         } else {
703             if (needsInit) {
704                 return switch (wrapper) {
705                     case BYTE -> FIELD_ACCESS_INIT_B;
706                     case CHAR -> FIELD_ACCESS_INIT_C;
707                     case SHORT -> FIELD_ACCESS_INIT_S;
708                     case BOOLEAN -> FIELD_ACCESS_INIT_Z;
709                     default -> needsCast ? FIELD_ACCESS_INIT_CAST : FIELD_ACCESS_INIT;
710                 };
711             } else {
712                 return switch (wrapper) {
713                     case BYTE -> FIELD_ACCESS_B;
714                     case CHAR -> FIELD_ACCESS_C;
715                     case SHORT -> FIELD_ACCESS_S;
716                     case BOOLEAN -> FIELD_ACCESS_Z;
717                     default -> needsCast ? FIELD_ACCESS_CAST : FIELD_ACCESS;
718                 };
719             }
720         }
721     }
722 
723     private static String unsafeMethodName(boolean isGetter, boolean isVolatile, Wrapper wrapper) {
724         var name = switch (wrapper) {
725             case BOOLEAN -> "Boolean";
726             case BYTE -> "Byte";
727             case CHAR -> "Char";
728             case SHORT -> "Short";
729             case INT -> "Int";
730             case FLOAT -> "Float";
731             case LONG -> "Long";
732             case DOUBLE -> "Double";
733             case OBJECT -> "Reference";
734             case VOID -> throw new InternalError();
735         };
736         var sb = new StringBuilder(3 + name.length() + (isVolatile ? 8 : 0))
737                 .append(isGetter ? "get" : "put")
738                 .append(name);
739         if (isVolatile) {
740             sb.append("Volatile");
741         }
742         return sb.toString();
743     }
744 
745     static LambdaForm makePreparedFieldLambdaForm(byte formOp, boolean isVolatile, int ftypeKind) {
746         boolean isGetter  = (formOp & 1) == (AF_GETFIELD & 1);
747         boolean isStatic  = (formOp >= AF_GETSTATIC);
748         boolean needsInit = (formOp >= AF_GETSTATIC_INIT);
749         boolean needsCast = (ftypeKind == FT_CHECKED_REF);
750         Wrapper fw = (needsCast ? Wrapper.OBJECT : ALL_WRAPPERS[ftypeKind]);
751         Class<?> ft = fw.primitiveType();
752         assert(ftypeKind(needsCast ? String.class : ft) == ftypeKind);
753 
754         // getObject, putIntVolatile, etc.
755         String unsafeMethodName = unsafeMethodName(isGetter, isVolatile, fw);
756         // isGetter and isStatic is reflected in field type; basic type clash for subwords
757         Kind kind = getFieldKind(isVolatile, needsInit, needsCast, fw);
758 
759         MethodType linkerType;
760         if (isGetter)
761             linkerType = MethodType.methodType(ft, Object.class, long.class);
762         else
763             linkerType = MethodType.methodType(void.class, Object.class, long.class, ft);
764         MemberName linker = new MemberName(Unsafe.class, unsafeMethodName, linkerType, REF_invokeVirtual);
765         try {
766             linker = IMPL_NAMES.resolveOrFail(REF_invokeVirtual, linker, null, LM_TRUSTED,
767                                               NoSuchMethodException.class);
768         } catch (ReflectiveOperationException ex) {
769             throw newInternalError(ex);
770         }
771 
772         // What is the external type of the lambda form?
773         MethodType mtype;
774         if (isGetter)
775             mtype = MethodType.methodType(ft);
776         else
777             mtype = MethodType.methodType(void.class, ft);
778         mtype = mtype.basicType();  // erase short to int, etc.
779         if (!isStatic)
780             mtype = mtype.insertParameterTypes(0, Object.class);
781         final int DMH_THIS  = 0;
782         final int ARG_BASE  = 1;
783         final int ARG_LIMIT = ARG_BASE + mtype.parameterCount();
784         // if this is for non-static access, the base pointer is stored at this index:
785         final int OBJ_BASE  = isStatic ? -1 : ARG_BASE;
786         // if this is for write access, the value to be written is stored at this index:
787         final int SET_VALUE  = isGetter ? -1 : ARG_LIMIT - 1;
788         int nameCursor = ARG_LIMIT;
789         final int F_HOLDER  = (isStatic ? nameCursor++ : -1);  // static base if any
790         final int F_OFFSET  = nameCursor++;  // Either static offset or field offset.
791         final int OBJ_CHECK = (OBJ_BASE >= 0 ? nameCursor++ : -1);
792         final int U_HOLDER  = nameCursor++;  // UNSAFE holder
793         final int INIT_BAR  = (needsInit ? nameCursor++ : -1);
794         final int PRE_CAST  = (needsCast && !isGetter ? nameCursor++ : -1);
795         final int LINKER_CALL = nameCursor++;
796         final int POST_CAST = (needsCast && isGetter ? nameCursor++ : -1);
797         final int RESULT    = nameCursor-1;  // either the call or the cast
798         Name[] names = invokeArguments(nameCursor - ARG_LIMIT, mtype);
799         if (needsInit)
800             names[INIT_BAR] = new Name(getFunction(NF_ensureInitialized), names[DMH_THIS]);
801         if (needsCast && !isGetter)
802             names[PRE_CAST] = new Name(getFunction(NF_checkCast), names[DMH_THIS], names[SET_VALUE]);
803         Object[] outArgs = new Object[1 + linkerType.parameterCount()];
804         assert(outArgs.length == (isGetter ? 3 : 4));
805         outArgs[0] = names[U_HOLDER] = new Name(getFunction(NF_UNSAFE));
806         if (isStatic) {
807             outArgs[1] = names[F_HOLDER]  = new Name(getFunction(NF_staticBase), names[DMH_THIS]);
808             outArgs[2] = names[F_OFFSET]  = new Name(getFunction(NF_staticOffset), names[DMH_THIS]);
809         } else {
810             outArgs[1] = names[OBJ_CHECK] = new Name(getFunction(NF_checkBase), names[OBJ_BASE]);
811             outArgs[2] = names[F_OFFSET]  = new Name(getFunction(NF_fieldOffset), names[DMH_THIS]);
812         }
813         if (!isGetter) {
814             outArgs[3] = (needsCast ? names[PRE_CAST] : names[SET_VALUE]);
815         }
816         for (Object a : outArgs)  assert(a != null);
817         names[LINKER_CALL] = new Name(linker, outArgs);
818         if (needsCast && isGetter)
819             names[POST_CAST] = new Name(getFunction(NF_checkCast), names[DMH_THIS], names[LINKER_CALL]);
820         for (Name n : names)  assert(n != null);
821 
822         LambdaForm form = LambdaForm.create(ARG_LIMIT, names, RESULT, kind);
823 
824         if (LambdaForm.debugNames()) {
825             // add some detail to the lambdaForm debugname,
826             // significant only for debugging
827             StringBuilder nameBuilder = new StringBuilder(unsafeMethodName);
828             if (isStatic) {
829                 nameBuilder.append("Static");
830             } else {
831                 nameBuilder.append("Field");
832             }
833             if (needsCast) {
834                 nameBuilder.append("Cast");
835             }
836             if (needsInit) {
837                 nameBuilder.append("Init");
838             }
839             LambdaForm.associateWithDebugName(form, nameBuilder.toString());
840         }
841 
842         // NF_UNSAFE uses field form, avoid circular dependency in interpreter
843         form.compileToBytecode();
844         return form;
845     }
846 
847     /**
848      * Pre-initialized NamedFunctions for bootstrapping purposes.
849      */
850     static final byte NF_internalMemberName = 0,
851             NF_internalMemberNameEnsureInit = 1,
852             NF_ensureInitialized = 2,
853             NF_fieldOffset = 3,
854             NF_checkBase = 4,
855             NF_staticBase = 5,
856             NF_staticOffset = 6,
857             NF_checkCast = 7,
858             NF_allocateInstance = 8,
859             NF_constructorMethod = 9,
860             NF_UNSAFE = 10,
861             NF_checkReceiver = 11,
862             NF_LIMIT = 12;
863 
864     private static final @Stable NamedFunction[] NFS = new NamedFunction[NF_LIMIT];
865 
866     private static NamedFunction getFunction(byte func) {
867         NamedFunction nf = NFS[func];
868         if (nf != null) {
869             return nf;
870         }
871         // Each nf must be statically invocable or we get tied up in our bootstraps.
872         nf = NFS[func] = createFunction(func);
873         assert(InvokerBytecodeGenerator.isStaticallyInvocable(nf));
874         return nf;
875     }
876 
877     private static final MethodType OBJ_OBJ_TYPE = MethodType.methodType(Object.class, Object.class);
878 
879     private static final MethodType LONG_OBJ_TYPE = MethodType.methodType(long.class, Object.class);
880 
881     private static NamedFunction createFunction(byte func) {
882         try {
883             switch (func) {
884                 case NF_internalMemberName:
885                     return getNamedFunction("internalMemberName", OBJ_OBJ_TYPE);
886                 case NF_internalMemberNameEnsureInit:
887                     return getNamedFunction("internalMemberNameEnsureInit", OBJ_OBJ_TYPE);
888                 case NF_ensureInitialized:
889                     return getNamedFunction("ensureInitialized", MethodType.methodType(void.class, Object.class));
890                 case NF_fieldOffset:
891                     return getNamedFunction("fieldOffset", LONG_OBJ_TYPE);
892                 case NF_checkBase:
893                     return getNamedFunction("checkBase", OBJ_OBJ_TYPE);
894                 case NF_staticBase:
895                     return getNamedFunction("staticBase", OBJ_OBJ_TYPE);
896                 case NF_staticOffset:
897                     return getNamedFunction("staticOffset", LONG_OBJ_TYPE);
898                 case NF_checkCast:
899                     return getNamedFunction("checkCast", MethodType.methodType(Object.class, Object.class, Object.class));
900                 case NF_allocateInstance:
901                     return getNamedFunction("allocateInstance", OBJ_OBJ_TYPE);
902                 case NF_constructorMethod:
903                     return getNamedFunction("constructorMethod", OBJ_OBJ_TYPE);
904                 case NF_UNSAFE:
905                     MemberName member = new MemberName(MethodHandleStatics.class, "UNSAFE", Unsafe.class, REF_getStatic);
906                     return new NamedFunction(
907                             MemberName.getFactory().resolveOrFail(REF_getStatic, member,
908                                                                   DirectMethodHandle.class, LM_TRUSTED,
909                                                                   NoSuchFieldException.class));
910                 case NF_checkReceiver:
911                     member = new MemberName(DirectMethodHandle.class, "checkReceiver", OBJ_OBJ_TYPE, REF_invokeVirtual);
912                     return new NamedFunction(
913                             MemberName.getFactory().resolveOrFail(REF_invokeVirtual, member,
914                                                                   DirectMethodHandle.class, LM_TRUSTED,
915                                                                   NoSuchMethodException.class));
916                 default:
917                     throw newInternalError("Unknown function: " + func);
918             }
919         } catch (ReflectiveOperationException ex) {
920             throw newInternalError(ex);
921         }
922     }
923 
924     private static NamedFunction getNamedFunction(String name, MethodType type)
925         throws ReflectiveOperationException
926     {
927         MemberName member = new MemberName(DirectMethodHandle.class, name, type, REF_invokeStatic);
928         return new NamedFunction(
929                 MemberName.getFactory().resolveOrFail(REF_invokeStatic, member,
930                                                       DirectMethodHandle.class, LM_TRUSTED,
931                                                       NoSuchMethodException.class));
932     }
933 
934     static {
935         // The Holder class will contain pre-generated DirectMethodHandles resolved
936         // speculatively using MemberName.getFactory().resolveOrNull. However, that
937         // doesn't initialize the class, which subtly breaks inlining etc. By forcing
938         // initialization of the Holder class we avoid these issues.
939         UNSAFE.ensureClassInitialized(Holder.class);
940     }
941 
942     /* Placeholder class for DirectMethodHandles generated ahead of time */
943     @AOTSafeClassInitializer
944     final class Holder {}
945 }