1 /*
  2  * Copyright (c) 2020, 2021, 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.vm.annotation.ForceInline;
 29 import jdk.internal.invoke.NativeEntryPoint;
 30 
 31 import static java.lang.invoke.LambdaForm.*;
 32 import static java.lang.invoke.MethodHandleNatives.Constants.LM_TRUSTED;
 33 import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeStatic;
 34 import static java.lang.invoke.MethodHandleStatics.newInternalError;
 35 
 36 /**
 37  * This class models a method handle to a native function. A native method handle is made up of a {@link NativeEntryPoint},
 38  * which is used to capture the characteristics of the native call (such as calling convention to be used,
 39  * or whether a native transition is required) and a <em>fallback</em> method handle, which can be used
 40  * when intrinsification of this method handle is not possible.
 41  */
 42 /*non-public*/ class NativeMethodHandle extends MethodHandle {
 43     final NativeEntryPoint nep;
 44 
 45     private NativeMethodHandle(MethodType type, LambdaForm form, NativeEntryPoint nep) {
 46         super(type, form);
 47         this.nep = nep;
 48     }
 49 
 50     /**
 51      * Creates a new native method handle with given {@link NativeEntryPoint} and <em>fallback</em> method handle.
 52      */
 53     public static MethodHandle make(NativeEntryPoint nep) {
 54         MethodType type = nep.type();
 55         if (!allTypesPrimitive(type))
 56             throw new IllegalArgumentException("Type must only contain primitives: " + type);
 57 
 58 
 59         LambdaForm lform = preparedLambdaForm(type);
 60         return new NativeMethodHandle(type, lform, nep);
 61     }
 62 
 63     private static boolean allTypesPrimitive(MethodType type) {
 64         if (!type.returnType().isPrimitive())
 65             return false;
 66 
 67         for (Class<?> pType : type.parameterArray()) {
 68             if (!pType.isPrimitive())
 69                 return false;
 70         }
 71 
 72         return true;
 73     }
 74 
 75     private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory();
 76 
 77     private static LambdaForm preparedLambdaForm(MethodType mtype) {
 78         int id = MethodTypeForm.LF_INVNATIVE;
 79         mtype = mtype.basicType();
 80         LambdaForm lform = mtype.form().cachedLambdaForm(id);
 81         if (lform != null) return lform;
 82         lform = makePreparedLambdaForm(mtype);
 83         return mtype.form().setCachedLambdaForm(id, lform);
 84     }
 85 
 86     private static LambdaForm makePreparedLambdaForm(MethodType mtype) {
 87         MethodType linkerType = mtype
 88                 .appendParameterTypes(Object.class); // NEP
 89         MemberName linker = new MemberName(MethodHandle.class, "linkToNative", linkerType, REF_invokeStatic);
 90         try {
 91             linker = IMPL_NAMES.resolveOrFail(REF_invokeStatic, linker, null, LM_TRUSTED, NoSuchMethodException.class);
 92         } catch (ReflectiveOperationException ex) {
 93             throw newInternalError(ex);
 94         }
 95         final int NMH_THIS = 0;
 96         final int ARG_BASE = 1;
 97         final int ARG_LIMIT = ARG_BASE + mtype.parameterCount();
 98         int nameCursor = ARG_LIMIT;
 99         final int GET_NEP = nameCursor++;
100         final int LINKER_CALL = nameCursor++;
101 
102         LambdaForm.Name[] names = arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
103         assert (names.length == nameCursor);
104 
105         names[GET_NEP] = new LambdaForm.Name(Lazy.NF_internalNativeEntryPoint, names[NMH_THIS]);
106 
107         Object[] outArgs = new Object[linkerType.parameterCount()];
108         System.arraycopy(names, ARG_BASE, outArgs, 0, mtype.parameterCount());
109         outArgs[outArgs.length - 1] = names[GET_NEP];
110         names[LINKER_CALL] = new LambdaForm.Name(linker, outArgs);
111 
112         LambdaForm lform = new LambdaForm(ARG_LIMIT, names, LAST_RESULT);
113         // This is a tricky bit of code.  Don't send it through the LF interpreter.
114         lform.compileToBytecode();
115         return lform;
116     }
117 
118     final
119     @Override
120     MethodHandle copyWith(MethodType mt, LambdaForm lf) {
121         assert (this.getClass() == NativeMethodHandle.class);  // must override in subclasses
122         return new NativeMethodHandle(mt, lf, nep);
123     }
124 
125     @Override
126     BoundMethodHandle rebind() {
127         return BoundMethodHandle.makeReinvoker(this);
128     }
129 
130     @ForceInline
131     static Object internalNativeEntryPoint(Object mh) {
132         return ((NativeMethodHandle)mh).nep;
133     }
134 
135     /**
136      * Pre-initialized NamedFunctions for bootstrapping purposes.
137      * Factored in an inner class to delay initialization until first usage.
138      */
139     private static class Lazy {
140 
141         static final NamedFunction
142                 NF_internalNativeEntryPoint;
143 
144         static {
145             try {
146                 Class<NativeMethodHandle> THIS_CLASS = NativeMethodHandle.class;
147                 NamedFunction[] nfs = new NamedFunction[]{
148                         NF_internalNativeEntryPoint = new NamedFunction(
149                                 THIS_CLASS.getDeclaredMethod("internalNativeEntryPoint", Object.class)),
150                 };
151                 for (NamedFunction nf : nfs) {
152                     // Each nf must be statically invocable or we get tied up in our bootstraps.
153                     assert (InvokerBytecodeGenerator.isStaticallyInvocable(nf.member)) : nf;
154                     nf.resolve();
155                 }
156             } catch (ReflectiveOperationException ex) {
157                 throw newInternalError(ex);
158             }
159         }
160     }
161 }