rt/emul/compact/src/main/java/java/lang/invoke/DirectMethodHandle.java
branchjdk8-b132
changeset 1646 c880a8a8803b
child 1653 bd151459ee4f
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/DirectMethodHandle.java	Sat Aug 09 11:11:13 2014 +0200
     1.3 @@ -0,0 +1,718 @@
     1.4 +/*
     1.5 + * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
     1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     1.7 + *
     1.8 + * This code is free software; you can redistribute it and/or modify it
     1.9 + * under the terms of the GNU General Public License version 2 only, as
    1.10 + * published by the Free Software Foundation.  Oracle designates this
    1.11 + * particular file as subject to the "Classpath" exception as provided
    1.12 + * by Oracle in the LICENSE file that accompanied this code.
    1.13 + *
    1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
    1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    1.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    1.17 + * version 2 for more details (a copy is included in the LICENSE file that
    1.18 + * accompanied this code).
    1.19 + *
    1.20 + * You should have received a copy of the GNU General Public License version
    1.21 + * 2 along with this work; if not, write to the Free Software Foundation,
    1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    1.23 + *
    1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    1.25 + * or visit www.oracle.com if you need additional information or have any
    1.26 + * questions.
    1.27 + */
    1.28 +
    1.29 +package java.lang.invoke;
    1.30 +
    1.31 +import sun.misc.Unsafe;
    1.32 +import java.lang.reflect.Method;
    1.33 +import java.util.Arrays;
    1.34 +import sun.invoke.util.VerifyAccess;
    1.35 +import static java.lang.invoke.MethodHandleNatives.Constants.*;
    1.36 +import static java.lang.invoke.LambdaForm.*;
    1.37 +import static java.lang.invoke.MethodTypeForm.*;
    1.38 +import static java.lang.invoke.MethodHandleStatics.*;
    1.39 +import java.lang.ref.WeakReference;
    1.40 +import java.lang.reflect.Field;
    1.41 +import sun.invoke.util.ValueConversions;
    1.42 +import sun.invoke.util.VerifyType;
    1.43 +import sun.invoke.util.Wrapper;
    1.44 +
    1.45 +/**
    1.46 + * The flavor of method handle which implements a constant reference
    1.47 + * to a class member.
    1.48 + * @author jrose
    1.49 + */
    1.50 +class DirectMethodHandle extends MethodHandle {
    1.51 +    final MemberName member;
    1.52 +
    1.53 +    // Constructors and factory methods in this class *must* be package scoped or private.
    1.54 +    private DirectMethodHandle(MethodType mtype, LambdaForm form, MemberName member) {
    1.55 +        super(mtype, form);
    1.56 +        if (!member.isResolved())  throw new InternalError();
    1.57 +
    1.58 +        if (member.getDeclaringClass().isInterface() &&
    1.59 +                member.isMethod() && !member.isAbstract()) {
    1.60 +            // Check for corner case: invokeinterface of Object method
    1.61 +            MemberName m = new MemberName(Object.class, member.getName(), member.getMethodType(), member.getReferenceKind());
    1.62 +            m = MemberName.getFactory().resolveOrNull(m.getReferenceKind(), m, null);
    1.63 +            if (m != null && m.isPublic()) {
    1.64 +                member = m;
    1.65 +            }
    1.66 +        }
    1.67 +
    1.68 +        this.member = member;
    1.69 +    }
    1.70 +
    1.71 +    // Factory methods:
    1.72 +    static DirectMethodHandle make(byte refKind, Class<?> receiver, MemberName member) {
    1.73 +        MethodType mtype = member.getMethodOrFieldType();
    1.74 +        if (!member.isStatic()) {
    1.75 +            if (!member.getDeclaringClass().isAssignableFrom(receiver) || member.isConstructor())
    1.76 +                throw new InternalError(member.toString());
    1.77 +            mtype = mtype.insertParameterTypes(0, receiver);
    1.78 +        }
    1.79 +        if (!member.isField()) {
    1.80 +            if (refKind == REF_invokeSpecial) {
    1.81 +                member = member.asSpecial();
    1.82 +                LambdaForm lform = preparedLambdaForm(member);
    1.83 +                return new Special(mtype, lform, member);
    1.84 +            } else {
    1.85 +                LambdaForm lform = preparedLambdaForm(member);
    1.86 +                return new DirectMethodHandle(mtype, lform, member);
    1.87 +            }
    1.88 +        } else {
    1.89 +            LambdaForm lform = preparedFieldLambdaForm(member);
    1.90 +            if (member.isStatic()) {
    1.91 +                long offset = MethodHandleNatives.staticFieldOffset(member);
    1.92 +                Object base = MethodHandleNatives.staticFieldBase(member);
    1.93 +                return new StaticAccessor(mtype, lform, member, base, offset);
    1.94 +            } else {
    1.95 +                long offset = MethodHandleNatives.objectFieldOffset(member);
    1.96 +                assert(offset == (int)offset);
    1.97 +                return new Accessor(mtype, lform, member, (int)offset);
    1.98 +            }
    1.99 +        }
   1.100 +    }
   1.101 +    static DirectMethodHandle make(Class<?> receiver, MemberName member) {
   1.102 +        byte refKind = member.getReferenceKind();
   1.103 +        if (refKind == REF_invokeSpecial)
   1.104 +            refKind =  REF_invokeVirtual;
   1.105 +        return make(refKind, receiver, member);
   1.106 +    }
   1.107 +    static DirectMethodHandle make(MemberName member) {
   1.108 +        if (member.isConstructor())
   1.109 +            return makeAllocator(member);
   1.110 +        return make(member.getDeclaringClass(), member);
   1.111 +    }
   1.112 +    static DirectMethodHandle make(Method method) {
   1.113 +        return make(method.getDeclaringClass(), new MemberName(method));
   1.114 +    }
   1.115 +    static DirectMethodHandle make(Field field) {
   1.116 +        return make(field.getDeclaringClass(), new MemberName(field));
   1.117 +    }
   1.118 +    private static DirectMethodHandle makeAllocator(MemberName ctor) {
   1.119 +        assert(ctor.isConstructor() && ctor.getName().equals("<init>"));
   1.120 +        Class<?> instanceClass = ctor.getDeclaringClass();
   1.121 +        ctor = ctor.asConstructor();
   1.122 +        assert(ctor.isConstructor() && ctor.getReferenceKind() == REF_newInvokeSpecial) : ctor;
   1.123 +        MethodType mtype = ctor.getMethodType().changeReturnType(instanceClass);
   1.124 +        LambdaForm lform = preparedLambdaForm(ctor);
   1.125 +        MemberName init = ctor.asSpecial();
   1.126 +        assert(init.getMethodType().returnType() == void.class);
   1.127 +        return new Constructor(mtype, lform, ctor, init, instanceClass);
   1.128 +    }
   1.129 +
   1.130 +    @Override
   1.131 +    MethodHandle copyWith(MethodType mt, LambdaForm lf) {
   1.132 +        return new DirectMethodHandle(mt, lf, member);
   1.133 +    }
   1.134 +
   1.135 +    @Override
   1.136 +    String internalProperties() {
   1.137 +        return "/DMH="+member.toString();
   1.138 +    }
   1.139 +
   1.140 +    //// Implementation methods.
   1.141 +    @Override
   1.142 +    MethodHandle viewAsType(MethodType newType) {
   1.143 +        return new DirectMethodHandle(newType, form, member);
   1.144 +    }
   1.145 +    @Override
   1.146 +    @ForceInline
   1.147 +    MemberName internalMemberName() {
   1.148 +        return member;
   1.149 +    }
   1.150 +
   1.151 +    @Override
   1.152 +    MethodHandle bindArgument(int pos, char basicType, Object value) {
   1.153 +        // If the member needs dispatching, do so.
   1.154 +        if (pos == 0 && basicType == 'L') {
   1.155 +            DirectMethodHandle concrete = maybeRebind(value);
   1.156 +            if (concrete != null)
   1.157 +                return concrete.bindReceiver(value);
   1.158 +        }
   1.159 +        return super.bindArgument(pos, basicType, value);
   1.160 +    }
   1.161 +
   1.162 +    @Override
   1.163 +    MethodHandle bindReceiver(Object receiver) {
   1.164 +        // If the member needs dispatching, do so.
   1.165 +        DirectMethodHandle concrete = maybeRebind(receiver);
   1.166 +        if (concrete != null)
   1.167 +            return concrete.bindReceiver(receiver);
   1.168 +        return super.bindReceiver(receiver);
   1.169 +    }
   1.170 +
   1.171 +    private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory();
   1.172 +
   1.173 +    private DirectMethodHandle maybeRebind(Object receiver) {
   1.174 +        if (receiver != null) {
   1.175 +            switch (member.getReferenceKind()) {
   1.176 +            case REF_invokeInterface:
   1.177 +            case REF_invokeVirtual:
   1.178 +                // Pre-dispatch the member.
   1.179 +                Class<?> concreteClass = receiver.getClass();
   1.180 +                MemberName concrete = new MemberName(concreteClass, member.getName(), member.getMethodType(), REF_invokeSpecial);
   1.181 +                concrete = IMPL_NAMES.resolveOrNull(REF_invokeSpecial, concrete, concreteClass);
   1.182 +                if (concrete != null)
   1.183 +                    return new DirectMethodHandle(type(), preparedLambdaForm(concrete), concrete);
   1.184 +                break;
   1.185 +            }
   1.186 +        }
   1.187 +        return null;
   1.188 +    }
   1.189 +
   1.190 +    /**
   1.191 +     * Create a LF which can invoke the given method.
   1.192 +     * Cache and share this structure among all methods with
   1.193 +     * the same basicType and refKind.
   1.194 +     */
   1.195 +    private static LambdaForm preparedLambdaForm(MemberName m) {
   1.196 +        assert(m.isInvocable()) : m;  // call preparedFieldLambdaForm instead
   1.197 +        MethodType mtype = m.getInvocationType().basicType();
   1.198 +        assert(!m.isMethodHandleInvoke() || "invokeBasic".equals(m.getName())) : m;
   1.199 +        int which;
   1.200 +        switch (m.getReferenceKind()) {
   1.201 +        case REF_invokeVirtual:    which = LF_INVVIRTUAL;    break;
   1.202 +        case REF_invokeStatic:     which = LF_INVSTATIC;     break;
   1.203 +        case REF_invokeSpecial:    which = LF_INVSPECIAL;    break;
   1.204 +        case REF_invokeInterface:  which = LF_INVINTERFACE;  break;
   1.205 +        case REF_newInvokeSpecial: which = LF_NEWINVSPECIAL; break;
   1.206 +        default:  throw new InternalError(m.toString());
   1.207 +        }
   1.208 +        if (which == LF_INVSTATIC && shouldBeInitialized(m)) {
   1.209 +            // precompute the barrier-free version:
   1.210 +            preparedLambdaForm(mtype, which);
   1.211 +            which = LF_INVSTATIC_INIT;
   1.212 +        }
   1.213 +        LambdaForm lform = preparedLambdaForm(mtype, which);
   1.214 +        maybeCompile(lform, m);
   1.215 +        assert(lform.methodType().dropParameterTypes(0, 1)
   1.216 +                .equals(m.getInvocationType().basicType()))
   1.217 +                : Arrays.asList(m, m.getInvocationType().basicType(), lform, lform.methodType());
   1.218 +        return lform;
   1.219 +    }
   1.220 +
   1.221 +    private static LambdaForm preparedLambdaForm(MethodType mtype, int which) {
   1.222 +        LambdaForm lform = mtype.form().cachedLambdaForm(which);
   1.223 +        if (lform != null)  return lform;
   1.224 +        lform = makePreparedLambdaForm(mtype, which);
   1.225 +        return mtype.form().setCachedLambdaForm(which, lform);
   1.226 +    }
   1.227 +
   1.228 +    private static LambdaForm makePreparedLambdaForm(MethodType mtype, int which) {
   1.229 +        boolean needsInit = (which == LF_INVSTATIC_INIT);
   1.230 +        boolean doesAlloc = (which == LF_NEWINVSPECIAL);
   1.231 +        String linkerName, lambdaName;
   1.232 +        switch (which) {
   1.233 +        case LF_INVVIRTUAL:    linkerName = "linkToVirtual";    lambdaName = "DMH.invokeVirtual";    break;
   1.234 +        case LF_INVSTATIC:     linkerName = "linkToStatic";     lambdaName = "DMH.invokeStatic";     break;
   1.235 +        case LF_INVSTATIC_INIT:linkerName = "linkToStatic";     lambdaName = "DMH.invokeStaticInit"; break;
   1.236 +        case LF_INVSPECIAL:    linkerName = "linkToSpecial";    lambdaName = "DMH.invokeSpecial";    break;
   1.237 +        case LF_INVINTERFACE:  linkerName = "linkToInterface";  lambdaName = "DMH.invokeInterface";  break;
   1.238 +        case LF_NEWINVSPECIAL: linkerName = "linkToSpecial";    lambdaName = "DMH.newInvokeSpecial"; break;
   1.239 +        default:  throw new InternalError("which="+which);
   1.240 +        }
   1.241 +        MethodType mtypeWithArg = mtype.appendParameterTypes(MemberName.class);
   1.242 +        if (doesAlloc)
   1.243 +            mtypeWithArg = mtypeWithArg
   1.244 +                    .insertParameterTypes(0, Object.class)  // insert newly allocated obj
   1.245 +                    .changeReturnType(void.class);          // <init> returns void
   1.246 +        MemberName linker = new MemberName(MethodHandle.class, linkerName, mtypeWithArg, REF_invokeStatic);
   1.247 +        try {
   1.248 +            linker = IMPL_NAMES.resolveOrFail(REF_invokeStatic, linker, null, NoSuchMethodException.class);
   1.249 +        } catch (ReflectiveOperationException ex) {
   1.250 +            throw newInternalError(ex);
   1.251 +        }
   1.252 +        final int DMH_THIS    = 0;
   1.253 +        final int ARG_BASE    = 1;
   1.254 +        final int ARG_LIMIT   = ARG_BASE + mtype.parameterCount();
   1.255 +        int nameCursor = ARG_LIMIT;
   1.256 +        final int NEW_OBJ     = (doesAlloc ? nameCursor++ : -1);
   1.257 +        final int GET_MEMBER  = nameCursor++;
   1.258 +        final int LINKER_CALL = nameCursor++;
   1.259 +        Name[] names = arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
   1.260 +        assert(names.length == nameCursor);
   1.261 +        if (doesAlloc) {
   1.262 +            // names = { argx,y,z,... new C, init method }
   1.263 +            names[NEW_OBJ] = new Name(Lazy.NF_allocateInstance, names[DMH_THIS]);
   1.264 +            names[GET_MEMBER] = new Name(Lazy.NF_constructorMethod, names[DMH_THIS]);
   1.265 +        } else if (needsInit) {
   1.266 +            names[GET_MEMBER] = new Name(Lazy.NF_internalMemberNameEnsureInit, names[DMH_THIS]);
   1.267 +        } else {
   1.268 +            names[GET_MEMBER] = new Name(Lazy.NF_internalMemberName, names[DMH_THIS]);
   1.269 +        }
   1.270 +        Object[] outArgs = Arrays.copyOfRange(names, ARG_BASE, GET_MEMBER+1, Object[].class);
   1.271 +        assert(outArgs[outArgs.length-1] == names[GET_MEMBER]);  // look, shifted args!
   1.272 +        int result = LambdaForm.LAST_RESULT;
   1.273 +        if (doesAlloc) {
   1.274 +            assert(outArgs[outArgs.length-2] == names[NEW_OBJ]);  // got to move this one
   1.275 +            System.arraycopy(outArgs, 0, outArgs, 1, outArgs.length-2);
   1.276 +            outArgs[0] = names[NEW_OBJ];
   1.277 +            result = NEW_OBJ;
   1.278 +        }
   1.279 +        names[LINKER_CALL] = new Name(linker, outArgs);
   1.280 +        lambdaName += "_" + LambdaForm.basicTypeSignature(mtype);
   1.281 +        LambdaForm lform = new LambdaForm(lambdaName, ARG_LIMIT, names, result);
   1.282 +        // This is a tricky bit of code.  Don't send it through the LF interpreter.
   1.283 +        lform.compileToBytecode();
   1.284 +        return lform;
   1.285 +    }
   1.286 +
   1.287 +    private static void maybeCompile(LambdaForm lform, MemberName m) {
   1.288 +        if (VerifyAccess.isSamePackage(m.getDeclaringClass(), MethodHandle.class))
   1.289 +            // Help along bootstrapping...
   1.290 +            lform.compileToBytecode();
   1.291 +    }
   1.292 +
   1.293 +    /** Static wrapper for DirectMethodHandle.internalMemberName. */
   1.294 +    @ForceInline
   1.295 +    /*non-public*/ static Object internalMemberName(Object mh) {
   1.296 +        return ((DirectMethodHandle)mh).member;
   1.297 +    }
   1.298 +
   1.299 +    /** Static wrapper for DirectMethodHandle.internalMemberName.
   1.300 +     * This one also forces initialization.
   1.301 +     */
   1.302 +    /*non-public*/ static Object internalMemberNameEnsureInit(Object mh) {
   1.303 +        DirectMethodHandle dmh = (DirectMethodHandle)mh;
   1.304 +        dmh.ensureInitialized();
   1.305 +        return dmh.member;
   1.306 +    }
   1.307 +
   1.308 +    /*non-public*/ static
   1.309 +    boolean shouldBeInitialized(MemberName member) {
   1.310 +        switch (member.getReferenceKind()) {
   1.311 +        case REF_invokeStatic:
   1.312 +        case REF_getStatic:
   1.313 +        case REF_putStatic:
   1.314 +        case REF_newInvokeSpecial:
   1.315 +            break;
   1.316 +        default:
   1.317 +            // No need to initialize the class on this kind of member.
   1.318 +            return false;
   1.319 +        }
   1.320 +        Class<?> cls = member.getDeclaringClass();
   1.321 +        if (cls == ValueConversions.class ||
   1.322 +            cls == MethodHandleImpl.class ||
   1.323 +            cls == Invokers.class) {
   1.324 +            // These guys have lots of <clinit> DMH creation but we know
   1.325 +            // the MHs will not be used until the system is booted.
   1.326 +            return false;
   1.327 +        }
   1.328 +        if (VerifyAccess.isSamePackage(MethodHandle.class, cls) ||
   1.329 +            VerifyAccess.isSamePackage(ValueConversions.class, cls)) {
   1.330 +            // It is a system class.  It is probably in the process of
   1.331 +            // being initialized, but we will help it along just to be safe.
   1.332 +            if (UNSAFE.shouldBeInitialized(cls)) {
   1.333 +                UNSAFE.ensureClassInitialized(cls);
   1.334 +            }
   1.335 +            return false;
   1.336 +        }
   1.337 +        return UNSAFE.shouldBeInitialized(cls);
   1.338 +    }
   1.339 +
   1.340 +    private static class EnsureInitialized extends ClassValue<WeakReference<Thread>> {
   1.341 +        @Override
   1.342 +        protected WeakReference<Thread> computeValue(Class<?> type) {
   1.343 +            UNSAFE.ensureClassInitialized(type);
   1.344 +            if (UNSAFE.shouldBeInitialized(type))
   1.345 +                // If the previous call didn't block, this can happen.
   1.346 +                // We are executing inside <clinit>.
   1.347 +                return new WeakReference<>(Thread.currentThread());
   1.348 +            return null;
   1.349 +        }
   1.350 +        static final EnsureInitialized INSTANCE = new EnsureInitialized();
   1.351 +    }
   1.352 +
   1.353 +    private void ensureInitialized() {
   1.354 +        if (checkInitialized(member)) {
   1.355 +            // The coast is clear.  Delete the <clinit> barrier.
   1.356 +            if (member.isField())
   1.357 +                updateForm(preparedFieldLambdaForm(member));
   1.358 +            else
   1.359 +                updateForm(preparedLambdaForm(member));
   1.360 +        }
   1.361 +    }
   1.362 +    private static boolean checkInitialized(MemberName member) {
   1.363 +        Class<?> defc = member.getDeclaringClass();
   1.364 +        WeakReference<Thread> ref = EnsureInitialized.INSTANCE.get(defc);
   1.365 +        if (ref == null) {
   1.366 +            return true;  // the final state
   1.367 +        }
   1.368 +        Thread clinitThread = ref.get();
   1.369 +        // Somebody may still be running defc.<clinit>.
   1.370 +        if (clinitThread == Thread.currentThread()) {
   1.371 +            // If anybody is running defc.<clinit>, it is this thread.
   1.372 +            if (UNSAFE.shouldBeInitialized(defc))
   1.373 +                // Yes, we are running it; keep the barrier for now.
   1.374 +                return false;
   1.375 +        } else {
   1.376 +            // We are in a random thread.  Block.
   1.377 +            UNSAFE.ensureClassInitialized(defc);
   1.378 +        }
   1.379 +        assert(!UNSAFE.shouldBeInitialized(defc));
   1.380 +        // put it into the final state
   1.381 +        EnsureInitialized.INSTANCE.remove(defc);
   1.382 +        return true;
   1.383 +    }
   1.384 +
   1.385 +    /*non-public*/ static void ensureInitialized(Object mh) {
   1.386 +        ((DirectMethodHandle)mh).ensureInitialized();
   1.387 +    }
   1.388 +
   1.389 +    /** This subclass represents invokespecial instructions. */
   1.390 +    static class Special extends DirectMethodHandle {
   1.391 +        private Special(MethodType mtype, LambdaForm form, MemberName member) {
   1.392 +            super(mtype, form, member);
   1.393 +        }
   1.394 +        @Override
   1.395 +        boolean isInvokeSpecial() {
   1.396 +            return true;
   1.397 +        }
   1.398 +        @Override
   1.399 +        MethodHandle viewAsType(MethodType newType) {
   1.400 +            return new Special(newType, form, member);
   1.401 +        }
   1.402 +    }
   1.403 +
   1.404 +    /** This subclass handles constructor references. */
   1.405 +    static class Constructor extends DirectMethodHandle {
   1.406 +        final MemberName initMethod;
   1.407 +        final Class<?>   instanceClass;
   1.408 +
   1.409 +        private Constructor(MethodType mtype, LambdaForm form, MemberName constructor,
   1.410 +                            MemberName initMethod, Class<?> instanceClass) {
   1.411 +            super(mtype, form, constructor);
   1.412 +            this.initMethod = initMethod;
   1.413 +            this.instanceClass = instanceClass;
   1.414 +            assert(initMethod.isResolved());
   1.415 +        }
   1.416 +        @Override
   1.417 +        MethodHandle viewAsType(MethodType newType) {
   1.418 +            return new Constructor(newType, form, member, initMethod, instanceClass);
   1.419 +        }
   1.420 +    }
   1.421 +
   1.422 +    /*non-public*/ static Object constructorMethod(Object mh) {
   1.423 +        Constructor dmh = (Constructor)mh;
   1.424 +        return dmh.initMethod;
   1.425 +    }
   1.426 +
   1.427 +    /*non-public*/ static Object allocateInstance(Object mh) throws InstantiationException {
   1.428 +        Constructor dmh = (Constructor)mh;
   1.429 +        return UNSAFE.allocateInstance(dmh.instanceClass);
   1.430 +    }
   1.431 +
   1.432 +    /** This subclass handles non-static field references. */
   1.433 +    static class Accessor extends DirectMethodHandle {
   1.434 +        final Class<?> fieldType;
   1.435 +        final int      fieldOffset;
   1.436 +        private Accessor(MethodType mtype, LambdaForm form, MemberName member,
   1.437 +                         int fieldOffset) {
   1.438 +            super(mtype, form, member);
   1.439 +            this.fieldType   = member.getFieldType();
   1.440 +            this.fieldOffset = fieldOffset;
   1.441 +        }
   1.442 +
   1.443 +        @Override Object checkCast(Object obj) {
   1.444 +            return fieldType.cast(obj);
   1.445 +        }
   1.446 +        @Override
   1.447 +        MethodHandle viewAsType(MethodType newType) {
   1.448 +            return new Accessor(newType, form, member, fieldOffset);
   1.449 +        }
   1.450 +    }
   1.451 +
   1.452 +    @ForceInline
   1.453 +    /*non-public*/ static long fieldOffset(Object accessorObj) {
   1.454 +        // Note: We return a long because that is what Unsafe.getObject likes.
   1.455 +        // We store a plain int because it is more compact.
   1.456 +        return ((Accessor)accessorObj).fieldOffset;
   1.457 +    }
   1.458 +
   1.459 +    @ForceInline
   1.460 +    /*non-public*/ static Object checkBase(Object obj) {
   1.461 +        // Note that the object's class has already been verified,
   1.462 +        // since the parameter type of the Accessor method handle
   1.463 +        // is either member.getDeclaringClass or a subclass.
   1.464 +        // This was verified in DirectMethodHandle.make.
   1.465 +        // Therefore, the only remaining check is for null.
   1.466 +        // Since this check is *not* guaranteed by Unsafe.getInt
   1.467 +        // and its siblings, we need to make an explicit one here.
   1.468 +        obj.getClass();  // maybe throw NPE
   1.469 +        return obj;
   1.470 +    }
   1.471 +
   1.472 +    /** This subclass handles static field references. */
   1.473 +    static class StaticAccessor extends DirectMethodHandle {
   1.474 +        final private Class<?> fieldType;
   1.475 +        final private Object   staticBase;
   1.476 +        final private long     staticOffset;
   1.477 +
   1.478 +        private StaticAccessor(MethodType mtype, LambdaForm form, MemberName member,
   1.479 +                               Object staticBase, long staticOffset) {
   1.480 +            super(mtype, form, member);
   1.481 +            this.fieldType    = member.getFieldType();
   1.482 +            this.staticBase   = staticBase;
   1.483 +            this.staticOffset = staticOffset;
   1.484 +        }
   1.485 +
   1.486 +        @Override Object checkCast(Object obj) {
   1.487 +            return fieldType.cast(obj);
   1.488 +        }
   1.489 +        @Override
   1.490 +        MethodHandle viewAsType(MethodType newType) {
   1.491 +            return new StaticAccessor(newType, form, member, staticBase, staticOffset);
   1.492 +        }
   1.493 +    }
   1.494 +
   1.495 +    @ForceInline
   1.496 +    /*non-public*/ static Object nullCheck(Object obj) {
   1.497 +        obj.getClass();
   1.498 +        return obj;
   1.499 +    }
   1.500 +
   1.501 +    @ForceInline
   1.502 +    /*non-public*/ static Object staticBase(Object accessorObj) {
   1.503 +        return ((StaticAccessor)accessorObj).staticBase;
   1.504 +    }
   1.505 +
   1.506 +    @ForceInline
   1.507 +    /*non-public*/ static long staticOffset(Object accessorObj) {
   1.508 +        return ((StaticAccessor)accessorObj).staticOffset;
   1.509 +    }
   1.510 +
   1.511 +    @ForceInline
   1.512 +    /*non-public*/ static Object checkCast(Object mh, Object obj) {
   1.513 +        return ((DirectMethodHandle) mh).checkCast(obj);
   1.514 +    }
   1.515 +
   1.516 +    Object checkCast(Object obj) {
   1.517 +        return member.getReturnType().cast(obj);
   1.518 +    }
   1.519 +
   1.520 +    // Caching machinery for field accessors:
   1.521 +    private static byte
   1.522 +            AF_GETFIELD        = 0,
   1.523 +            AF_PUTFIELD        = 1,
   1.524 +            AF_GETSTATIC       = 2,
   1.525 +            AF_PUTSTATIC       = 3,
   1.526 +            AF_GETSTATIC_INIT  = 4,
   1.527 +            AF_PUTSTATIC_INIT  = 5,
   1.528 +            AF_LIMIT           = 6;
   1.529 +    // Enumerate the different field kinds using Wrapper,
   1.530 +    // with an extra case added for checked references.
   1.531 +    private static int
   1.532 +            FT_LAST_WRAPPER    = Wrapper.values().length-1,
   1.533 +            FT_UNCHECKED_REF   = Wrapper.OBJECT.ordinal(),
   1.534 +            FT_CHECKED_REF     = FT_LAST_WRAPPER+1,
   1.535 +            FT_LIMIT           = FT_LAST_WRAPPER+2;
   1.536 +    private static int afIndex(byte formOp, boolean isVolatile, int ftypeKind) {
   1.537 +        return ((formOp * FT_LIMIT * 2)
   1.538 +                + (isVolatile ? FT_LIMIT : 0)
   1.539 +                + ftypeKind);
   1.540 +    }
   1.541 +    private static final LambdaForm[] ACCESSOR_FORMS
   1.542 +            = new LambdaForm[afIndex(AF_LIMIT, false, 0)];
   1.543 +    private static int ftypeKind(Class<?> ftype) {
   1.544 +        if (ftype.isPrimitive())
   1.545 +            return Wrapper.forPrimitiveType(ftype).ordinal();
   1.546 +        else if (VerifyType.isNullReferenceConversion(Object.class, ftype))
   1.547 +            return FT_UNCHECKED_REF;
   1.548 +        else
   1.549 +            return FT_CHECKED_REF;
   1.550 +    }
   1.551 +
   1.552 +    /**
   1.553 +     * Create a LF which can access the given field.
   1.554 +     * Cache and share this structure among all fields with
   1.555 +     * the same basicType and refKind.
   1.556 +     */
   1.557 +    private static LambdaForm preparedFieldLambdaForm(MemberName m) {
   1.558 +        Class<?> ftype = m.getFieldType();
   1.559 +        boolean isVolatile = m.isVolatile();
   1.560 +        byte formOp;
   1.561 +        switch (m.getReferenceKind()) {
   1.562 +        case REF_getField:      formOp = AF_GETFIELD;    break;
   1.563 +        case REF_putField:      formOp = AF_PUTFIELD;    break;
   1.564 +        case REF_getStatic:     formOp = AF_GETSTATIC;   break;
   1.565 +        case REF_putStatic:     formOp = AF_PUTSTATIC;   break;
   1.566 +        default:  throw new InternalError(m.toString());
   1.567 +        }
   1.568 +        if (shouldBeInitialized(m)) {
   1.569 +            // precompute the barrier-free version:
   1.570 +            preparedFieldLambdaForm(formOp, isVolatile, ftype);
   1.571 +            assert((AF_GETSTATIC_INIT - AF_GETSTATIC) ==
   1.572 +                   (AF_PUTSTATIC_INIT - AF_PUTSTATIC));
   1.573 +            formOp += (AF_GETSTATIC_INIT - AF_GETSTATIC);
   1.574 +        }
   1.575 +        LambdaForm lform = preparedFieldLambdaForm(formOp, isVolatile, ftype);
   1.576 +        maybeCompile(lform, m);
   1.577 +        assert(lform.methodType().dropParameterTypes(0, 1)
   1.578 +                .equals(m.getInvocationType().basicType()))
   1.579 +                : Arrays.asList(m, m.getInvocationType().basicType(), lform, lform.methodType());
   1.580 +        return lform;
   1.581 +    }
   1.582 +    private static LambdaForm preparedFieldLambdaForm(byte formOp, boolean isVolatile, Class<?> ftype) {
   1.583 +        int afIndex = afIndex(formOp, isVolatile, ftypeKind(ftype));
   1.584 +        LambdaForm lform = ACCESSOR_FORMS[afIndex];
   1.585 +        if (lform != null)  return lform;
   1.586 +        lform = makePreparedFieldLambdaForm(formOp, isVolatile, ftypeKind(ftype));
   1.587 +        ACCESSOR_FORMS[afIndex] = lform;  // don't bother with a CAS
   1.588 +        return lform;
   1.589 +    }
   1.590 +
   1.591 +    private static LambdaForm makePreparedFieldLambdaForm(byte formOp, boolean isVolatile, int ftypeKind) {
   1.592 +        boolean isGetter  = (formOp & 1) == (AF_GETFIELD & 1);
   1.593 +        boolean isStatic  = (formOp >= AF_GETSTATIC);
   1.594 +        boolean needsInit = (formOp >= AF_GETSTATIC_INIT);
   1.595 +        boolean needsCast = (ftypeKind == FT_CHECKED_REF);
   1.596 +        Wrapper fw = (needsCast ? Wrapper.OBJECT : Wrapper.values()[ftypeKind]);
   1.597 +        Class<?> ft = fw.primitiveType();
   1.598 +        assert(ftypeKind(needsCast ? String.class : ft) == ftypeKind);
   1.599 +        String tname  = fw.primitiveSimpleName();
   1.600 +        String ctname = Character.toUpperCase(tname.charAt(0)) + tname.substring(1);
   1.601 +        if (isVolatile)  ctname += "Volatile";
   1.602 +        String getOrPut = (isGetter ? "get" : "put");
   1.603 +        String linkerName = (getOrPut + ctname);  // getObject, putIntVolatile, etc.
   1.604 +        MethodType linkerType;
   1.605 +        if (isGetter)
   1.606 +            linkerType = MethodType.methodType(ft, Object.class, long.class);
   1.607 +        else
   1.608 +            linkerType = MethodType.methodType(void.class, Object.class, long.class, ft);
   1.609 +        MemberName linker = new MemberName(Unsafe.class, linkerName, linkerType, REF_invokeVirtual);
   1.610 +        try {
   1.611 +            linker = IMPL_NAMES.resolveOrFail(REF_invokeVirtual, linker, null, NoSuchMethodException.class);
   1.612 +        } catch (ReflectiveOperationException ex) {
   1.613 +            throw newInternalError(ex);
   1.614 +        }
   1.615 +
   1.616 +        // What is the external type of the lambda form?
   1.617 +        MethodType mtype;
   1.618 +        if (isGetter)
   1.619 +            mtype = MethodType.methodType(ft);
   1.620 +        else
   1.621 +            mtype = MethodType.methodType(void.class, ft);
   1.622 +        mtype = mtype.basicType();  // erase short to int, etc.
   1.623 +        if (!isStatic)
   1.624 +            mtype = mtype.insertParameterTypes(0, Object.class);
   1.625 +        final int DMH_THIS  = 0;
   1.626 +        final int ARG_BASE  = 1;
   1.627 +        final int ARG_LIMIT = ARG_BASE + mtype.parameterCount();
   1.628 +        // if this is for non-static access, the base pointer is stored at this index:
   1.629 +        final int OBJ_BASE  = isStatic ? -1 : ARG_BASE;
   1.630 +        // if this is for write access, the value to be written is stored at this index:
   1.631 +        final int SET_VALUE  = isGetter ? -1 : ARG_LIMIT - 1;
   1.632 +        int nameCursor = ARG_LIMIT;
   1.633 +        final int F_HOLDER  = (isStatic ? nameCursor++ : -1);  // static base if any
   1.634 +        final int F_OFFSET  = nameCursor++;  // Either static offset or field offset.
   1.635 +        final int OBJ_CHECK = (OBJ_BASE >= 0 ? nameCursor++ : -1);
   1.636 +        final int INIT_BAR  = (needsInit ? nameCursor++ : -1);
   1.637 +        final int PRE_CAST  = (needsCast && !isGetter ? nameCursor++ : -1);
   1.638 +        final int LINKER_CALL = nameCursor++;
   1.639 +        final int POST_CAST = (needsCast && isGetter ? nameCursor++ : -1);
   1.640 +        final int RESULT    = nameCursor-1;  // either the call or the cast
   1.641 +        Name[] names = arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
   1.642 +        if (needsInit)
   1.643 +            names[INIT_BAR] = new Name(Lazy.NF_ensureInitialized, names[DMH_THIS]);
   1.644 +        if (needsCast && !isGetter)
   1.645 +            names[PRE_CAST] = new Name(Lazy.NF_checkCast, names[DMH_THIS], names[SET_VALUE]);
   1.646 +        Object[] outArgs = new Object[1 + linkerType.parameterCount()];
   1.647 +        assert(outArgs.length == (isGetter ? 3 : 4));
   1.648 +        outArgs[0] = UNSAFE;
   1.649 +        if (isStatic) {
   1.650 +            outArgs[1] = names[F_HOLDER]  = new Name(Lazy.NF_staticBase, names[DMH_THIS]);
   1.651 +            outArgs[2] = names[F_OFFSET]  = new Name(Lazy.NF_staticOffset, names[DMH_THIS]);
   1.652 +        } else {
   1.653 +            outArgs[1] = names[OBJ_CHECK] = new Name(Lazy.NF_checkBase, names[OBJ_BASE]);
   1.654 +            outArgs[2] = names[F_OFFSET]  = new Name(Lazy.NF_fieldOffset, names[DMH_THIS]);
   1.655 +        }
   1.656 +        if (!isGetter) {
   1.657 +            outArgs[3] = (needsCast ? names[PRE_CAST] : names[SET_VALUE]);
   1.658 +        }
   1.659 +        for (Object a : outArgs)  assert(a != null);
   1.660 +        names[LINKER_CALL] = new Name(linker, outArgs);
   1.661 +        if (needsCast && isGetter)
   1.662 +            names[POST_CAST] = new Name(Lazy.NF_checkCast, names[DMH_THIS], names[LINKER_CALL]);
   1.663 +        for (Name n : names)  assert(n != null);
   1.664 +        String fieldOrStatic = (isStatic ? "Static" : "Field");
   1.665 +        String lambdaName = (linkerName + fieldOrStatic);  // significant only for debugging
   1.666 +        if (needsCast)  lambdaName += "Cast";
   1.667 +        if (needsInit)  lambdaName += "Init";
   1.668 +        return new LambdaForm(lambdaName, ARG_LIMIT, names, RESULT);
   1.669 +    }
   1.670 +
   1.671 +    /**
   1.672 +     * Pre-initialized NamedFunctions for bootstrapping purposes.
   1.673 +     * Factored in an inner class to delay initialization until first usage.
   1.674 +     */
   1.675 +    private static class Lazy {
   1.676 +        static final NamedFunction
   1.677 +                NF_internalMemberName,
   1.678 +                NF_internalMemberNameEnsureInit,
   1.679 +                NF_ensureInitialized,
   1.680 +                NF_fieldOffset,
   1.681 +                NF_checkBase,
   1.682 +                NF_staticBase,
   1.683 +                NF_staticOffset,
   1.684 +                NF_checkCast,
   1.685 +                NF_allocateInstance,
   1.686 +                NF_constructorMethod;
   1.687 +        static {
   1.688 +            try {
   1.689 +                NamedFunction nfs[] = {
   1.690 +                        NF_internalMemberName = new NamedFunction(DirectMethodHandle.class
   1.691 +                                .getDeclaredMethod("internalMemberName", Object.class)),
   1.692 +                        NF_internalMemberNameEnsureInit = new NamedFunction(DirectMethodHandle.class
   1.693 +                                .getDeclaredMethod("internalMemberNameEnsureInit", Object.class)),
   1.694 +                        NF_ensureInitialized = new NamedFunction(DirectMethodHandle.class
   1.695 +                                .getDeclaredMethod("ensureInitialized", Object.class)),
   1.696 +                        NF_fieldOffset = new NamedFunction(DirectMethodHandle.class
   1.697 +                                .getDeclaredMethod("fieldOffset", Object.class)),
   1.698 +                        NF_checkBase = new NamedFunction(DirectMethodHandle.class
   1.699 +                                .getDeclaredMethod("checkBase", Object.class)),
   1.700 +                        NF_staticBase = new NamedFunction(DirectMethodHandle.class
   1.701 +                                .getDeclaredMethod("staticBase", Object.class)),
   1.702 +                        NF_staticOffset = new NamedFunction(DirectMethodHandle.class
   1.703 +                                .getDeclaredMethod("staticOffset", Object.class)),
   1.704 +                        NF_checkCast = new NamedFunction(DirectMethodHandle.class
   1.705 +                                .getDeclaredMethod("checkCast", Object.class, Object.class)),
   1.706 +                        NF_allocateInstance = new NamedFunction(DirectMethodHandle.class
   1.707 +                                .getDeclaredMethod("allocateInstance", Object.class)),
   1.708 +                        NF_constructorMethod = new NamedFunction(DirectMethodHandle.class
   1.709 +                                .getDeclaredMethod("constructorMethod", Object.class))
   1.710 +                };
   1.711 +                for (NamedFunction nf : nfs) {
   1.712 +                    // Each nf must be statically invocable or we get tied up in our bootstraps.
   1.713 +                    assert(InvokerBytecodeGenerator.isStaticallyInvocable(nf.member)) : nf;
   1.714 +                    nf.resolve();
   1.715 +                }
   1.716 +            } catch (ReflectiveOperationException ex) {
   1.717 +                throw newInternalError(ex);
   1.718 +            }
   1.719 +        }
   1.720 +    }
   1.721 +}