rev 12972 : 8140606: Update library code to use internal Unsafe
Reviewed-by: duke
1 /*
2 * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.lang.invoke;
27
28 import jdk.internal.misc.Unsafe;
29 import java.lang.reflect.Method;
30 import java.util.Arrays;
31 import sun.invoke.util.VerifyAccess;
32 import static java.lang.invoke.MethodHandleNatives.Constants.*;
33 import static java.lang.invoke.LambdaForm.*;
34 import static java.lang.invoke.MethodTypeForm.*;
35 import static java.lang.invoke.MethodHandleStatics.*;
36 import java.lang.ref.WeakReference;
37 import java.lang.reflect.Field;
38 import java.util.Objects;
39 import sun.invoke.util.ValueConversions;
40 import sun.invoke.util.VerifyType;
41 import sun.invoke.util.Wrapper;
42
43 /**
44 * The flavor of method handle which implements a constant reference
45 * to a class member.
46 * @author jrose
47 */
48 class DirectMethodHandle extends MethodHandle {
49 final MemberName member;
50
51 // Constructors and factory methods in this class *must* be package scoped or private.
52 private DirectMethodHandle(MethodType mtype, LambdaForm form, MemberName member) {
53 super(mtype, form);
54 if (!member.isResolved()) throw new InternalError();
55
56 if (member.getDeclaringClass().isInterface() &&
57 member.isMethod() && !member.isAbstract()) {
58 // Check for corner case: invokeinterface of Object method
59 MemberName m = new MemberName(Object.class, member.getName(), member.getMethodType(), member.getReferenceKind());
60 m = MemberName.getFactory().resolveOrNull(m.getReferenceKind(), m, null);
61 if (m != null && m.isPublic()) {
62 assert(member.getReferenceKind() == m.getReferenceKind()); // else this.form is wrong
63 member = m;
64 }
65 }
66
67 this.member = member;
68 }
69
70 // Factory methods:
71 static DirectMethodHandle make(byte refKind, Class<?> receiver, MemberName member) {
72 MethodType mtype = member.getMethodOrFieldType();
73 if (!member.isStatic()) {
74 if (!member.getDeclaringClass().isAssignableFrom(receiver) || member.isConstructor())
75 throw new InternalError(member.toString());
76 mtype = mtype.insertParameterTypes(0, receiver);
77 }
78 if (!member.isField()) {
79 if (refKind == REF_invokeSpecial) {
80 member = member.asSpecial();
81 LambdaForm lform = preparedLambdaForm(member);
82 return new Special(mtype, lform, member);
83 } else {
84 LambdaForm lform = preparedLambdaForm(member);
85 return new DirectMethodHandle(mtype, lform, member);
86 }
87 } else {
88 LambdaForm lform = preparedFieldLambdaForm(member);
89 if (member.isStatic()) {
90 long offset = MethodHandleNatives.staticFieldOffset(member);
91 Object base = MethodHandleNatives.staticFieldBase(member);
92 return new StaticAccessor(mtype, lform, member, base, offset);
93 } else {
94 long offset = MethodHandleNatives.objectFieldOffset(member);
95 assert(offset == (int)offset);
96 return new Accessor(mtype, lform, member, (int)offset);
97 }
98 }
99 }
100 static DirectMethodHandle make(Class<?> receiver, MemberName member) {
101 byte refKind = member.getReferenceKind();
102 if (refKind == REF_invokeSpecial)
103 refKind = REF_invokeVirtual;
104 return make(refKind, receiver, member);
105 }
106 static DirectMethodHandle make(MemberName member) {
107 if (member.isConstructor())
108 return makeAllocator(member);
109 return make(member.getDeclaringClass(), member);
110 }
111 static DirectMethodHandle make(Method method) {
112 return make(method.getDeclaringClass(), new MemberName(method));
113 }
114 static DirectMethodHandle make(Field field) {
115 return make(field.getDeclaringClass(), new MemberName(field));
116 }
117 private static DirectMethodHandle makeAllocator(MemberName ctor) {
118 assert(ctor.isConstructor() && ctor.getName().equals("<init>"));
119 Class<?> instanceClass = ctor.getDeclaringClass();
120 ctor = ctor.asConstructor();
121 assert(ctor.isConstructor() && ctor.getReferenceKind() == REF_newInvokeSpecial) : ctor;
122 MethodType mtype = ctor.getMethodType().changeReturnType(instanceClass);
123 LambdaForm lform = preparedLambdaForm(ctor);
124 MemberName init = ctor.asSpecial();
125 assert(init.getMethodType().returnType() == void.class);
126 return new Constructor(mtype, lform, ctor, init, instanceClass);
127 }
128
129 @Override
130 BoundMethodHandle rebind() {
131 return BoundMethodHandle.makeReinvoker(this);
132 }
133
134 @Override
135 MethodHandle copyWith(MethodType mt, LambdaForm lf) {
136 assert(this.getClass() == DirectMethodHandle.class); // must override in subclasses
137 return new DirectMethodHandle(mt, lf, member);
138 }
139
140 @Override
141 String internalProperties() {
142 return "\n& DMH.MN="+internalMemberName();
143 }
144
145 //// Implementation methods.
146 @Override
147 @ForceInline
148 MemberName internalMemberName() {
149 return member;
150 }
151
152 private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory();
153
154 /**
155 * Create a LF which can invoke the given method.
156 * Cache and share this structure among all methods with
157 * the same basicType and refKind.
158 */
159 private static LambdaForm preparedLambdaForm(MemberName m) {
160 assert(m.isInvocable()) : m; // call preparedFieldLambdaForm instead
161 MethodType mtype = m.getInvocationType().basicType();
162 assert(!m.isMethodHandleInvoke() || "invokeBasic".equals(m.getName())) : m;
163 int which;
164 switch (m.getReferenceKind()) {
165 case REF_invokeVirtual: which = LF_INVVIRTUAL; break;
166 case REF_invokeStatic: which = LF_INVSTATIC; break;
167 case REF_invokeSpecial: which = LF_INVSPECIAL; break;
168 case REF_invokeInterface: which = LF_INVINTERFACE; break;
169 case REF_newInvokeSpecial: which = LF_NEWINVSPECIAL; break;
170 default: throw new InternalError(m.toString());
171 }
172 if (which == LF_INVSTATIC && shouldBeInitialized(m)) {
173 // precompute the barrier-free version:
174 preparedLambdaForm(mtype, which);
175 which = LF_INVSTATIC_INIT;
176 }
177 LambdaForm lform = preparedLambdaForm(mtype, which);
178 maybeCompile(lform, m);
179 assert(lform.methodType().dropParameterTypes(0, 1)
180 .equals(m.getInvocationType().basicType()))
181 : Arrays.asList(m, m.getInvocationType().basicType(), lform, lform.methodType());
182 return lform;
183 }
184
185 private static LambdaForm preparedLambdaForm(MethodType mtype, int which) {
186 LambdaForm lform = mtype.form().cachedLambdaForm(which);
187 if (lform != null) return lform;
188 lform = makePreparedLambdaForm(mtype, which);
189 return mtype.form().setCachedLambdaForm(which, lform);
190 }
191
192 private static LambdaForm makePreparedLambdaForm(MethodType mtype, int which) {
193 boolean needsInit = (which == LF_INVSTATIC_INIT);
194 boolean doesAlloc = (which == LF_NEWINVSPECIAL);
195 String linkerName, lambdaName;
196 switch (which) {
197 case LF_INVVIRTUAL: linkerName = "linkToVirtual"; lambdaName = "DMH.invokeVirtual"; break;
198 case LF_INVSTATIC: linkerName = "linkToStatic"; lambdaName = "DMH.invokeStatic"; break;
199 case LF_INVSTATIC_INIT:linkerName = "linkToStatic"; lambdaName = "DMH.invokeStaticInit"; break;
200 case LF_INVSPECIAL: linkerName = "linkToSpecial"; lambdaName = "DMH.invokeSpecial"; break;
201 case LF_INVINTERFACE: linkerName = "linkToInterface"; lambdaName = "DMH.invokeInterface"; break;
202 case LF_NEWINVSPECIAL: linkerName = "linkToSpecial"; lambdaName = "DMH.newInvokeSpecial"; break;
203 default: throw new InternalError("which="+which);
204 }
205 MethodType mtypeWithArg = mtype.appendParameterTypes(MemberName.class);
206 if (doesAlloc)
207 mtypeWithArg = mtypeWithArg
208 .insertParameterTypes(0, Object.class) // insert newly allocated obj
209 .changeReturnType(void.class); // <init> returns void
210 MemberName linker = new MemberName(MethodHandle.class, linkerName, mtypeWithArg, REF_invokeStatic);
211 try {
212 linker = IMPL_NAMES.resolveOrFail(REF_invokeStatic, linker, null, NoSuchMethodException.class);
213 } catch (ReflectiveOperationException ex) {
214 throw newInternalError(ex);
215 }
216 final int DMH_THIS = 0;
217 final int ARG_BASE = 1;
218 final int ARG_LIMIT = ARG_BASE + mtype.parameterCount();
219 int nameCursor = ARG_LIMIT;
220 final int NEW_OBJ = (doesAlloc ? nameCursor++ : -1);
221 final int GET_MEMBER = nameCursor++;
222 final int LINKER_CALL = nameCursor++;
223 Name[] names = arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
224 assert(names.length == nameCursor);
225 if (doesAlloc) {
226 // names = { argx,y,z,... new C, init method }
227 names[NEW_OBJ] = new Name(Lazy.NF_allocateInstance, names[DMH_THIS]);
228 names[GET_MEMBER] = new Name(Lazy.NF_constructorMethod, names[DMH_THIS]);
229 } else if (needsInit) {
230 names[GET_MEMBER] = new Name(Lazy.NF_internalMemberNameEnsureInit, names[DMH_THIS]);
231 } else {
232 names[GET_MEMBER] = new Name(Lazy.NF_internalMemberName, names[DMH_THIS]);
233 }
234 assert(findDirectMethodHandle(names[GET_MEMBER]) == names[DMH_THIS]);
235 Object[] outArgs = Arrays.copyOfRange(names, ARG_BASE, GET_MEMBER+1, Object[].class);
236 assert(outArgs[outArgs.length-1] == names[GET_MEMBER]); // look, shifted args!
237 int result = LAST_RESULT;
238 if (doesAlloc) {
239 assert(outArgs[outArgs.length-2] == names[NEW_OBJ]); // got to move this one
240 System.arraycopy(outArgs, 0, outArgs, 1, outArgs.length-2);
241 outArgs[0] = names[NEW_OBJ];
242 result = NEW_OBJ;
243 }
244 names[LINKER_CALL] = new Name(linker, outArgs);
245 lambdaName += "_" + shortenSignature(basicTypeSignature(mtype));
246 LambdaForm lform = new LambdaForm(lambdaName, ARG_LIMIT, names, result);
247 // This is a tricky bit of code. Don't send it through the LF interpreter.
248 lform.compileToBytecode();
249 return lform;
250 }
251
252 static Object findDirectMethodHandle(Name name) {
253 if (name.function == Lazy.NF_internalMemberName ||
254 name.function == Lazy.NF_internalMemberNameEnsureInit ||
255 name.function == Lazy.NF_constructorMethod) {
256 assert(name.arguments.length == 1);
257 return name.arguments[0];
258 }
259 return null;
260 }
261
262 private static void maybeCompile(LambdaForm lform, MemberName m) {
263 if (VerifyAccess.isSamePackage(m.getDeclaringClass(), MethodHandle.class))
264 // Help along bootstrapping...
265 lform.compileToBytecode();
266 }
267
268 /** Static wrapper for DirectMethodHandle.internalMemberName. */
269 @ForceInline
270 /*non-public*/ static Object internalMemberName(Object mh) {
271 return ((DirectMethodHandle)mh).member;
272 }
273
274 /** Static wrapper for DirectMethodHandle.internalMemberName.
275 * This one also forces initialization.
276 */
277 /*non-public*/ static Object internalMemberNameEnsureInit(Object mh) {
278 DirectMethodHandle dmh = (DirectMethodHandle)mh;
279 dmh.ensureInitialized();
280 return dmh.member;
281 }
282
283 /*non-public*/ static
284 boolean shouldBeInitialized(MemberName member) {
285 switch (member.getReferenceKind()) {
286 case REF_invokeStatic:
287 case REF_getStatic:
288 case REF_putStatic:
289 case REF_newInvokeSpecial:
290 break;
291 default:
292 // No need to initialize the class on this kind of member.
293 return false;
294 }
295 Class<?> cls = member.getDeclaringClass();
296 if (cls == ValueConversions.class ||
297 cls == MethodHandleImpl.class ||
298 cls == Invokers.class) {
299 // These guys have lots of <clinit> DMH creation but we know
300 // the MHs will not be used until the system is booted.
301 return false;
302 }
303 if (VerifyAccess.isSamePackage(MethodHandle.class, cls) ||
304 VerifyAccess.isSamePackage(ValueConversions.class, cls)) {
305 // It is a system class. It is probably in the process of
306 // being initialized, but we will help it along just to be safe.
307 if (UNSAFE.shouldBeInitialized(cls)) {
308 UNSAFE.ensureClassInitialized(cls);
309 }
310 return false;
311 }
312 return UNSAFE.shouldBeInitialized(cls);
313 }
314
315 private static class EnsureInitialized extends ClassValue<WeakReference<Thread>> {
316 @Override
317 protected WeakReference<Thread> computeValue(Class<?> type) {
318 UNSAFE.ensureClassInitialized(type);
319 if (UNSAFE.shouldBeInitialized(type))
320 // If the previous call didn't block, this can happen.
321 // We are executing inside <clinit>.
322 return new WeakReference<>(Thread.currentThread());
323 return null;
324 }
325 static final EnsureInitialized INSTANCE = new EnsureInitialized();
326 }
327
328 private void ensureInitialized() {
329 if (checkInitialized(member)) {
330 // The coast is clear. Delete the <clinit> barrier.
331 if (member.isField())
332 updateForm(preparedFieldLambdaForm(member));
333 else
334 updateForm(preparedLambdaForm(member));
335 }
336 }
337 private static boolean checkInitialized(MemberName member) {
338 Class<?> defc = member.getDeclaringClass();
339 WeakReference<Thread> ref = EnsureInitialized.INSTANCE.get(defc);
340 if (ref == null) {
341 return true; // the final state
342 }
343 Thread clinitThread = ref.get();
344 // Somebody may still be running defc.<clinit>.
345 if (clinitThread == Thread.currentThread()) {
346 // If anybody is running defc.<clinit>, it is this thread.
347 if (UNSAFE.shouldBeInitialized(defc))
348 // Yes, we are running it; keep the barrier for now.
349 return false;
350 } else {
351 // We are in a random thread. Block.
352 UNSAFE.ensureClassInitialized(defc);
353 }
354 assert(!UNSAFE.shouldBeInitialized(defc));
355 // put it into the final state
356 EnsureInitialized.INSTANCE.remove(defc);
357 return true;
358 }
359
360 /*non-public*/ static void ensureInitialized(Object mh) {
361 ((DirectMethodHandle)mh).ensureInitialized();
362 }
363
364 /** This subclass represents invokespecial instructions. */
365 static class Special extends DirectMethodHandle {
366 private Special(MethodType mtype, LambdaForm form, MemberName member) {
367 super(mtype, form, member);
368 }
369 @Override
370 boolean isInvokeSpecial() {
371 return true;
372 }
373 @Override
374 MethodHandle copyWith(MethodType mt, LambdaForm lf) {
375 return new Special(mt, lf, member);
376 }
377 }
378
379 /** This subclass handles constructor references. */
380 static class Constructor extends DirectMethodHandle {
381 final MemberName initMethod;
382 final Class<?> instanceClass;
383
384 private Constructor(MethodType mtype, LambdaForm form, MemberName constructor,
385 MemberName initMethod, Class<?> instanceClass) {
386 super(mtype, form, constructor);
387 this.initMethod = initMethod;
388 this.instanceClass = instanceClass;
389 assert(initMethod.isResolved());
390 }
391 @Override
392 MethodHandle copyWith(MethodType mt, LambdaForm lf) {
393 return new Constructor(mt, lf, member, initMethod, instanceClass);
394 }
395 }
396
397 /*non-public*/ static Object constructorMethod(Object mh) {
398 Constructor dmh = (Constructor)mh;
399 return dmh.initMethod;
400 }
401
402 /*non-public*/ static Object allocateInstance(Object mh) throws InstantiationException {
403 Constructor dmh = (Constructor)mh;
404 return UNSAFE.allocateInstance(dmh.instanceClass);
405 }
406
407 /** This subclass handles non-static field references. */
408 static class Accessor extends DirectMethodHandle {
409 final Class<?> fieldType;
410 final int fieldOffset;
411 private Accessor(MethodType mtype, LambdaForm form, MemberName member,
412 int fieldOffset) {
413 super(mtype, form, member);
414 this.fieldType = member.getFieldType();
415 this.fieldOffset = fieldOffset;
416 }
417
418 @Override Object checkCast(Object obj) {
419 return fieldType.cast(obj);
420 }
421 @Override
422 MethodHandle copyWith(MethodType mt, LambdaForm lf) {
423 return new Accessor(mt, lf, member, fieldOffset);
424 }
425 }
426
427 @ForceInline
428 /*non-public*/ static long fieldOffset(Object accessorObj) {
429 // Note: We return a long because that is what Unsafe.getObject likes.
430 // We store a plain int because it is more compact.
431 return ((Accessor)accessorObj).fieldOffset;
432 }
433
434 @ForceInline
435 /*non-public*/ static Object checkBase(Object obj) {
436 // Note that the object's class has already been verified,
437 // since the parameter type of the Accessor method handle
438 // is either member.getDeclaringClass or a subclass.
439 // This was verified in DirectMethodHandle.make.
440 // Therefore, the only remaining check is for null.
441 // Since this check is *not* guaranteed by Unsafe.getInt
442 // and its siblings, we need to make an explicit one here.
443 return Objects.requireNonNull(obj);
444 }
445
446 /** This subclass handles static field references. */
447 static class StaticAccessor extends DirectMethodHandle {
448 private final Class<?> fieldType;
449 private final Object staticBase;
450 private final long staticOffset;
451
452 private StaticAccessor(MethodType mtype, LambdaForm form, MemberName member,
453 Object staticBase, long staticOffset) {
454 super(mtype, form, member);
455 this.fieldType = member.getFieldType();
456 this.staticBase = staticBase;
457 this.staticOffset = staticOffset;
458 }
459
460 @Override Object checkCast(Object obj) {
461 return fieldType.cast(obj);
462 }
463 @Override
464 MethodHandle copyWith(MethodType mt, LambdaForm lf) {
465 return new StaticAccessor(mt, lf, member, staticBase, staticOffset);
466 }
467 }
468
469 @ForceInline
470 /*non-public*/ static Object nullCheck(Object obj) {
471 return Objects.requireNonNull(obj);
472 }
473
474 @ForceInline
475 /*non-public*/ static Object staticBase(Object accessorObj) {
476 return ((StaticAccessor)accessorObj).staticBase;
477 }
478
479 @ForceInline
480 /*non-public*/ static long staticOffset(Object accessorObj) {
481 return ((StaticAccessor)accessorObj).staticOffset;
482 }
483
484 @ForceInline
485 /*non-public*/ static Object checkCast(Object mh, Object obj) {
486 return ((DirectMethodHandle) mh).checkCast(obj);
487 }
488
489 Object checkCast(Object obj) {
490 return member.getReturnType().cast(obj);
491 }
492
493 // Caching machinery for field accessors:
494 private static byte
495 AF_GETFIELD = 0,
496 AF_PUTFIELD = 1,
497 AF_GETSTATIC = 2,
498 AF_PUTSTATIC = 3,
499 AF_GETSTATIC_INIT = 4,
500 AF_PUTSTATIC_INIT = 5,
501 AF_LIMIT = 6;
502 // Enumerate the different field kinds using Wrapper,
503 // with an extra case added for checked references.
504 private static int
505 FT_LAST_WRAPPER = Wrapper.values().length-1,
506 FT_UNCHECKED_REF = Wrapper.OBJECT.ordinal(),
507 FT_CHECKED_REF = FT_LAST_WRAPPER+1,
508 FT_LIMIT = FT_LAST_WRAPPER+2;
509 private static int afIndex(byte formOp, boolean isVolatile, int ftypeKind) {
510 return ((formOp * FT_LIMIT * 2)
511 + (isVolatile ? FT_LIMIT : 0)
512 + ftypeKind);
513 }
514 private static final LambdaForm[] ACCESSOR_FORMS
515 = new LambdaForm[afIndex(AF_LIMIT, false, 0)];
516 private static int ftypeKind(Class<?> ftype) {
517 if (ftype.isPrimitive())
518 return Wrapper.forPrimitiveType(ftype).ordinal();
519 else if (VerifyType.isNullReferenceConversion(Object.class, ftype))
520 return FT_UNCHECKED_REF;
521 else
522 return FT_CHECKED_REF;
523 }
524
525 /**
526 * Create a LF which can access the given field.
527 * Cache and share this structure among all fields with
528 * the same basicType and refKind.
529 */
530 private static LambdaForm preparedFieldLambdaForm(MemberName m) {
531 Class<?> ftype = m.getFieldType();
532 boolean isVolatile = m.isVolatile();
533 byte formOp;
534 switch (m.getReferenceKind()) {
535 case REF_getField: formOp = AF_GETFIELD; break;
536 case REF_putField: formOp = AF_PUTFIELD; break;
537 case REF_getStatic: formOp = AF_GETSTATIC; break;
538 case REF_putStatic: formOp = AF_PUTSTATIC; break;
539 default: throw new InternalError(m.toString());
540 }
541 if (shouldBeInitialized(m)) {
542 // precompute the barrier-free version:
543 preparedFieldLambdaForm(formOp, isVolatile, ftype);
544 assert((AF_GETSTATIC_INIT - AF_GETSTATIC) ==
545 (AF_PUTSTATIC_INIT - AF_PUTSTATIC));
546 formOp += (AF_GETSTATIC_INIT - AF_GETSTATIC);
547 }
548 LambdaForm lform = preparedFieldLambdaForm(formOp, isVolatile, ftype);
549 maybeCompile(lform, m);
550 assert(lform.methodType().dropParameterTypes(0, 1)
551 .equals(m.getInvocationType().basicType()))
552 : Arrays.asList(m, m.getInvocationType().basicType(), lform, lform.methodType());
553 return lform;
554 }
555 private static LambdaForm preparedFieldLambdaForm(byte formOp, boolean isVolatile, Class<?> ftype) {
556 int afIndex = afIndex(formOp, isVolatile, ftypeKind(ftype));
557 LambdaForm lform = ACCESSOR_FORMS[afIndex];
558 if (lform != null) return lform;
559 lform = makePreparedFieldLambdaForm(formOp, isVolatile, ftypeKind(ftype));
560 ACCESSOR_FORMS[afIndex] = lform; // don't bother with a CAS
561 return lform;
562 }
563
564 private static LambdaForm makePreparedFieldLambdaForm(byte formOp, boolean isVolatile, int ftypeKind) {
565 boolean isGetter = (formOp & 1) == (AF_GETFIELD & 1);
566 boolean isStatic = (formOp >= AF_GETSTATIC);
567 boolean needsInit = (formOp >= AF_GETSTATIC_INIT);
568 boolean needsCast = (ftypeKind == FT_CHECKED_REF);
569 Wrapper fw = (needsCast ? Wrapper.OBJECT : Wrapper.values()[ftypeKind]);
570 Class<?> ft = fw.primitiveType();
571 assert(ftypeKind(needsCast ? String.class : ft) == ftypeKind);
572 String tname = fw.primitiveSimpleName();
573 String ctname = Character.toUpperCase(tname.charAt(0)) + tname.substring(1);
574 if (isVolatile) ctname += "Volatile";
575 String getOrPut = (isGetter ? "get" : "put");
576 String linkerName = (getOrPut + ctname); // getObject, putIntVolatile, etc.
577 MethodType linkerType;
578 if (isGetter)
579 linkerType = MethodType.methodType(ft, Object.class, long.class);
580 else
581 linkerType = MethodType.methodType(void.class, Object.class, long.class, ft);
582 MemberName linker = new MemberName(Unsafe.class, linkerName, linkerType, REF_invokeVirtual);
583 try {
584 linker = IMPL_NAMES.resolveOrFail(REF_invokeVirtual, linker, null, NoSuchMethodException.class);
585 } catch (ReflectiveOperationException ex) {
586 throw newInternalError(ex);
587 }
588
589 // What is the external type of the lambda form?
590 MethodType mtype;
591 if (isGetter)
592 mtype = MethodType.methodType(ft);
593 else
594 mtype = MethodType.methodType(void.class, ft);
595 mtype = mtype.basicType(); // erase short to int, etc.
596 if (!isStatic)
597 mtype = mtype.insertParameterTypes(0, Object.class);
598 final int DMH_THIS = 0;
599 final int ARG_BASE = 1;
600 final int ARG_LIMIT = ARG_BASE + mtype.parameterCount();
601 // if this is for non-static access, the base pointer is stored at this index:
602 final int OBJ_BASE = isStatic ? -1 : ARG_BASE;
603 // if this is for write access, the value to be written is stored at this index:
604 final int SET_VALUE = isGetter ? -1 : ARG_LIMIT - 1;
605 int nameCursor = ARG_LIMIT;
606 final int F_HOLDER = (isStatic ? nameCursor++ : -1); // static base if any
607 final int F_OFFSET = nameCursor++; // Either static offset or field offset.
608 final int OBJ_CHECK = (OBJ_BASE >= 0 ? nameCursor++ : -1);
609 final int INIT_BAR = (needsInit ? nameCursor++ : -1);
610 final int PRE_CAST = (needsCast && !isGetter ? nameCursor++ : -1);
611 final int LINKER_CALL = nameCursor++;
612 final int POST_CAST = (needsCast && isGetter ? nameCursor++ : -1);
613 final int RESULT = nameCursor-1; // either the call or the cast
614 Name[] names = arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
615 if (needsInit)
616 names[INIT_BAR] = new Name(Lazy.NF_ensureInitialized, names[DMH_THIS]);
617 if (needsCast && !isGetter)
618 names[PRE_CAST] = new Name(Lazy.NF_checkCast, names[DMH_THIS], names[SET_VALUE]);
619 Object[] outArgs = new Object[1 + linkerType.parameterCount()];
620 assert(outArgs.length == (isGetter ? 3 : 4));
621 outArgs[0] = UNSAFE;
622 if (isStatic) {
623 outArgs[1] = names[F_HOLDER] = new Name(Lazy.NF_staticBase, names[DMH_THIS]);
624 outArgs[2] = names[F_OFFSET] = new Name(Lazy.NF_staticOffset, names[DMH_THIS]);
625 } else {
626 outArgs[1] = names[OBJ_CHECK] = new Name(Lazy.NF_checkBase, names[OBJ_BASE]);
627 outArgs[2] = names[F_OFFSET] = new Name(Lazy.NF_fieldOffset, names[DMH_THIS]);
628 }
629 if (!isGetter) {
630 outArgs[3] = (needsCast ? names[PRE_CAST] : names[SET_VALUE]);
631 }
632 for (Object a : outArgs) assert(a != null);
633 names[LINKER_CALL] = new Name(linker, outArgs);
634 if (needsCast && isGetter)
635 names[POST_CAST] = new Name(Lazy.NF_checkCast, names[DMH_THIS], names[LINKER_CALL]);
636 for (Name n : names) assert(n != null);
637 String fieldOrStatic = (isStatic ? "Static" : "Field");
638 String lambdaName = (linkerName + fieldOrStatic); // significant only for debugging
639 if (needsCast) lambdaName += "Cast";
640 if (needsInit) lambdaName += "Init";
641 return new LambdaForm(lambdaName, ARG_LIMIT, names, RESULT);
642 }
643
644 /**
645 * Pre-initialized NamedFunctions for bootstrapping purposes.
646 * Factored in an inner class to delay initialization until first usage.
647 */
648 private static class Lazy {
649 static final NamedFunction
650 NF_internalMemberName,
651 NF_internalMemberNameEnsureInit,
652 NF_ensureInitialized,
653 NF_fieldOffset,
654 NF_checkBase,
655 NF_staticBase,
656 NF_staticOffset,
657 NF_checkCast,
658 NF_allocateInstance,
659 NF_constructorMethod;
660 static {
661 try {
662 NamedFunction nfs[] = {
663 NF_internalMemberName = new NamedFunction(DirectMethodHandle.class
664 .getDeclaredMethod("internalMemberName", Object.class)),
665 NF_internalMemberNameEnsureInit = new NamedFunction(DirectMethodHandle.class
666 .getDeclaredMethod("internalMemberNameEnsureInit", Object.class)),
667 NF_ensureInitialized = new NamedFunction(DirectMethodHandle.class
668 .getDeclaredMethod("ensureInitialized", Object.class)),
669 NF_fieldOffset = new NamedFunction(DirectMethodHandle.class
670 .getDeclaredMethod("fieldOffset", Object.class)),
671 NF_checkBase = new NamedFunction(DirectMethodHandle.class
672 .getDeclaredMethod("checkBase", Object.class)),
673 NF_staticBase = new NamedFunction(DirectMethodHandle.class
674 .getDeclaredMethod("staticBase", Object.class)),
675 NF_staticOffset = new NamedFunction(DirectMethodHandle.class
676 .getDeclaredMethod("staticOffset", Object.class)),
677 NF_checkCast = new NamedFunction(DirectMethodHandle.class
678 .getDeclaredMethod("checkCast", Object.class, Object.class)),
679 NF_allocateInstance = new NamedFunction(DirectMethodHandle.class
680 .getDeclaredMethod("allocateInstance", Object.class)),
681 NF_constructorMethod = new NamedFunction(DirectMethodHandle.class
682 .getDeclaredMethod("constructorMethod", Object.class))
683 };
684 for (NamedFunction nf : nfs) {
685 // Each nf must be statically invocable or we get tied up in our bootstraps.
686 assert(InvokerBytecodeGenerator.isStaticallyInvocable(nf.member)) : nf;
687 nf.resolve();
688 }
689 } catch (ReflectiveOperationException ex) {
690 throw newInternalError(ex);
691 }
692 }
693 }
694 }
--- EOF ---