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     final MethodHandle fallback;
 45 
 46     private NativeMethodHandle(MethodType type, LambdaForm form, MethodHandle fallback, NativeEntryPoint nep) {
 47         super(type, form);
 48         this.fallback = fallback;
 49         this.nep = nep;
 50     }
 51 
 52     /**
 53      * Creates a new native method handle with given {@link NativeEntryPoint} and <em>fallback</em> method handle.
 54      */
 55     public static MethodHandle make(NativeEntryPoint nep, MethodHandle fallback) {
 56         MethodType type = nep.type();
 57         if (!allTypesPrimitive(type))
 58             throw new IllegalArgumentException("Type must only contain primitives: " + type);
 59 
 60         if (type != fallback.type())
 61             throw new IllegalArgumentException("Type of fallback must match: " + type + " != " + fallback.type());
 62 
 63         LambdaForm lform = preparedLambdaForm(type);
 64         return new NativeMethodHandle(type, lform, fallback, nep);
 65     }
 66 
 67     private static boolean allTypesPrimitive(MethodType type) {
 68         if (!type.returnType().isPrimitive())
 69             return false;
 70 
 71         for (Class<?> pType : type.parameterArray()) {
 72             if (!pType.isPrimitive())
 73                 return false;
 74         }
 75 
 76         return true;
 77     }
 78 
 79     private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory();
 80 
 81     private static LambdaForm preparedLambdaForm(MethodType mtype) {
 82         int id = MethodTypeForm.LF_INVNATIVE;
 83         mtype = mtype.basicType();
 84         LambdaForm lform = mtype.form().cachedLambdaForm(id);
 85         if (lform != null) return lform;
 86         lform = makePreparedLambdaForm(mtype);
 87         return mtype.form().setCachedLambdaForm(id, lform);
 88     }
 89 
 90     private static LambdaForm makePreparedLambdaForm(MethodType mtype) {
 91         MethodType linkerType = mtype.insertParameterTypes(0, MethodHandle.class)
 92                 .appendParameterTypes(Object.class);
 93         MemberName linker = new MemberName(MethodHandle.class, "linkToNative", linkerType, REF_invokeStatic);
 94         try {
 95             linker = IMPL_NAMES.resolveOrFail(REF_invokeStatic, linker, null, LM_TRUSTED, NoSuchMethodException.class);
 96         } catch (ReflectiveOperationException ex) {
 97             throw newInternalError(ex);
 98         }
 99         final int NMH_THIS = 0;
100         final int ARG_BASE = 1;
101         final int ARG_LIMIT = ARG_BASE + mtype.parameterCount();
102         int nameCursor = ARG_LIMIT;
103         final int GET_FALLBACK = nameCursor++;
104         final int GET_NEP = nameCursor++;
105         final int LINKER_CALL = nameCursor++;
106         LambdaForm.Name[] names = arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
107         assert (names.length == nameCursor);
108         names[GET_FALLBACK] = new LambdaForm.Name(Lazy.NF_internalFallback, names[NMH_THIS]);
109         names[GET_NEP] = new LambdaForm.Name(Lazy.NF_internalNativeEntryPoint, names[NMH_THIS]);
110         Object[] outArgs = new Object[linkerType.parameterCount()];
111         // Need to pass fallback here so we can call it without destroying the receiver register!!
112         outArgs[0] = names[GET_FALLBACK];
113         System.arraycopy(names, ARG_BASE, outArgs, 1, mtype.parameterCount());
114         outArgs[outArgs.length - 1] = names[GET_NEP];
115         names[LINKER_CALL] = new LambdaForm.Name(linker, outArgs);
116         LambdaForm lform = new LambdaForm(ARG_LIMIT, names, LAST_RESULT);
117         // This is a tricky bit of code.  Don't send it through the LF interpreter.
118         lform.compileToBytecode();
119         return lform;
120     }
121 
122     final
123     @Override
124     MethodHandle copyWith(MethodType mt, LambdaForm lf) {
125         assert (this.getClass() == NativeMethodHandle.class);  // must override in subclasses
126         return new NativeMethodHandle(mt, lf, fallback, nep);
127     }
128 
129     @Override
130     BoundMethodHandle rebind() {
131         return BoundMethodHandle.makeReinvoker(this);
132     }
133 
134     @ForceInline
135     static Object internalNativeEntryPoint(Object mh) {
136         return ((NativeMethodHandle)mh).nep;
137     }
138 
139     @ForceInline
140     static MethodHandle internalFallback(Object mh) {
141         return ((NativeMethodHandle)mh).fallback;
142     }
143 
144     /**
145      * Pre-initialized NamedFunctions for bootstrapping purposes.
146      * Factored in an inner class to delay initialization until first usage.
147      */
148     private static class Lazy {
149 
150         static final NamedFunction
151                 NF_internalNativeEntryPoint;
152         static final NamedFunction
153                 NF_internalFallback;
154 
155         static {
156             try {
157                 Class<NativeMethodHandle> THIS_CLASS = NativeMethodHandle.class;
158                 NamedFunction[] nfs = new NamedFunction[]{
159                         NF_internalNativeEntryPoint = new NamedFunction(
160                                 THIS_CLASS.getDeclaredMethod("internalNativeEntryPoint", Object.class)),
161                         NF_internalFallback = new NamedFunction(
162                                 THIS_CLASS.getDeclaredMethod("internalFallback", Object.class))
163                 };
164                 for (NamedFunction nf : nfs) {
165                     // Each nf must be statically invocable or we get tied up in our bootstraps.
166                     assert (InvokerBytecodeGenerator.isStaticallyInvocable(nf.member)) : nf;
167                     nf.resolve();
168                 }
169             } catch (ReflectiveOperationException ex) {
170                 throw newInternalError(ex);
171             }
172         }
173     }
174 }