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