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