< prev index next >

src/java.base/share/classes/java/lang/invoke/NativeMethodHandle.java

Print this page

 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 }

 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 }
< prev index next >