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