< prev index next >

src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/ProgrammableUpcallHandler.java

Print this page

  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 jdk.internal.foreign.abi;
 27 
 28 import jdk.incubator.foreign.MemoryAddress;
 29 import jdk.incubator.foreign.MemoryLayouts;
 30 import jdk.incubator.foreign.MemorySegment;

 31 import jdk.incubator.foreign.ResourceScope;
 32 import jdk.incubator.foreign.SegmentAllocator;
 33 import jdk.internal.access.JavaLangInvokeAccess;
 34 import jdk.internal.access.SharedSecrets;
 35 import jdk.internal.foreign.MemoryAddressImpl;
 36 import sun.security.action.GetPropertyAction;
 37 
 38 import java.lang.invoke.MethodHandle;
 39 import java.lang.invoke.MethodHandles;
 40 import java.lang.invoke.MethodType;
 41 import java.lang.invoke.VarHandle;
 42 import java.util.Arrays;
 43 import java.util.List;
 44 import java.util.Map;
 45 import java.util.Objects;
 46 import java.util.stream.Stream;
 47 
 48 import static java.lang.invoke.MethodHandles.dropArguments;

 49 import static java.lang.invoke.MethodHandles.filterReturnValue;
 50 import static java.lang.invoke.MethodHandles.identity;
 51 import static java.lang.invoke.MethodHandles.insertArguments;
 52 import static java.lang.invoke.MethodHandles.lookup;
 53 import static java.lang.invoke.MethodType.methodType;
 54 import static jdk.internal.foreign.abi.SharedUtils.mergeArguments;
 55 import static sun.security.action.GetBooleanAction.privilegedGetProperty;
 56 
 57 /**
 58  * This class implements upcall invocation from native code through a so called 'universal adapter'. A universal upcall adapter
 59  * takes an array of storage pointers, which describes the state of the CPU at the time of the upcall. This can be used
 60  * by the Java code to fetch the upcall arguments and to store the results to the desired location, as per system ABI.
 61  */
 62 public class ProgrammableUpcallHandler {
 63     private static final boolean DEBUG =
 64         privilegedGetProperty("jdk.internal.foreign.ProgrammableUpcallHandler.DEBUG");
 65     private static final boolean USE_SPEC = Boolean.parseBoolean(
 66         GetPropertyAction.privilegedGetProperty("jdk.internal.foreign.ProgrammableUpcallHandler.USE_SPEC", "true"));
 67     private static final boolean USE_INTRINSICS = Boolean.parseBoolean(
 68         GetPropertyAction.privilegedGetProperty("jdk.internal.foreign.ProgrammableUpcallHandler.USE_INTRINSICS", "true"));
 69 
 70     private static final JavaLangInvokeAccess JLI = SharedSecrets.getJavaLangInvokeAccess();
 71 
 72     private static final VarHandle VH_LONG = MemoryLayouts.JAVA_LONG.varHandle(long.class);
 73 
 74     private static final MethodHandle MH_invokeMoves;
 75     private static final MethodHandle MH_invokeInterpBindings;
 76 
 77     static {
 78         try {
 79             MethodHandles.Lookup lookup = lookup();
 80             MH_invokeMoves = lookup.findStatic(ProgrammableUpcallHandler.class, "invokeMoves",
 81                     methodType(void.class, MemoryAddress.class, MethodHandle.class,
 82                                Binding.VMLoad[].class, Binding.VMStore[].class, ABIDescriptor.class, BufferLayout.class));
 83             MH_invokeInterpBindings = lookup.findStatic(ProgrammableUpcallHandler.class, "invokeInterpBindings",
 84                     methodType(Object.class, Object[].class, MethodHandle.class, Map.class, Map.class,
 85                             CallingSequence.class, long.class));
 86         } catch (ReflectiveOperationException e) {
 87             throw new InternalError(e);
 88         }
 89     }
 90 
 91     public static UpcallHandler make(ABIDescriptor abi, MethodHandle target, CallingSequence callingSequence) {
 92         Binding.VMLoad[] argMoves = argMoveBindings(callingSequence);
 93         Binding.VMStore[] retMoves = retMoveBindings(callingSequence);
 94 
 95         boolean isSimple = !(retMoves.length > 1);
 96 
 97         Class<?> llReturn = !isSimple
 98             ? Object[].class
 99             : retMoves.length == 1
100                 ? retMoves[0].type()
101                 : void.class;
102         Class<?>[] llParams = Arrays.stream(argMoves).map(Binding.Move::type).toArray(Class<?>[]::new);
103         MethodType llType = MethodType.methodType(llReturn, llParams);
104 
105         MethodHandle doBindings;
106         long bufferCopySize = SharedUtils.bufferCopySize(callingSequence);
107         if (USE_SPEC && isSimple) {
108             doBindings = specializedBindingHandle(target, callingSequence, llReturn, bufferCopySize);
109             assert doBindings.type() == llType;
110         } else {
111             Map<VMStorage, Integer> argIndices = SharedUtils.indexMap(argMoves);
112             Map<VMStorage, Integer> retIndices = SharedUtils.indexMap(retMoves);
113             target = target.asSpreader(Object[].class, callingSequence.methodType().parameterCount());
114             doBindings = insertArguments(MH_invokeInterpBindings, 1, target, argIndices, retIndices, callingSequence,
115                     bufferCopySize);
116             doBindings = doBindings.asCollector(Object[].class, llType.parameterCount());
117             doBindings = doBindings.asType(llType);
118         }
119 
120         long entryPoint;
121         boolean usesStackArgs = argMoveBindingsStream(callingSequence)
122                 .map(Binding.VMLoad::storage)
123                 .anyMatch(s -> abi.arch.isStackType(s.type()));
124         if (USE_INTRINSICS && isSimple && !usesStackArgs && supportsOptimizedUpcalls()) {
125             checkPrimitive(doBindings.type());
126             JLI.ensureCustomized(doBindings);
127             VMStorage[] args = Arrays.stream(argMoves).map(Binding.Move::storage).toArray(VMStorage[]::new);
128             VMStorage[] rets = Arrays.stream(retMoves).map(Binding.Move::storage).toArray(VMStorage[]::new);
129             CallRegs conv = new CallRegs(args, rets);
130             entryPoint = allocateOptimizedUpcallStub(doBindings, abi, conv);
131         } else {
132             BufferLayout layout = BufferLayout.of(abi);
133             MethodHandle doBindingsErased = doBindings.asSpreader(Object[].class, doBindings.type().parameterCount());
134             MethodHandle invokeMoves = insertArguments(MH_invokeMoves, 1, doBindingsErased, argMoves, retMoves, abi, layout);
135             entryPoint = allocateUpcallStub(invokeMoves, abi, layout);
136         }
137         return () -> entryPoint;
138     }
139 
140     private static void checkPrimitive(MethodType type) {
141         if (!type.returnType().isPrimitive()
142                 || type.parameterList().stream().anyMatch(p -> !p.isPrimitive()))
143             throw new IllegalArgumentException("MethodHandle type must be primitive: " + type);
144     }
145 
146     private static Stream<Binding.VMLoad> argMoveBindingsStream(CallingSequence callingSequence) {
147         return callingSequence.argumentBindings()
148                 .filter(Binding.VMLoad.class::isInstance)
149                 .map(Binding.VMLoad.class::cast);
150     }
151 
152     private static Binding.VMLoad[] argMoveBindings(CallingSequence callingSequence) {
153         return argMoveBindingsStream(callingSequence)
154                 .toArray(Binding.VMLoad[]::new);
155     }
156 
157     private static Binding.VMStore[] retMoveBindings(CallingSequence callingSequence) {

  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 jdk.internal.foreign.abi;
 27 
 28 import jdk.incubator.foreign.MemoryAddress;

 29 import jdk.incubator.foreign.MemorySegment;
 30 import jdk.incubator.foreign.NativeSymbol;
 31 import jdk.incubator.foreign.ResourceScope;
 32 import jdk.incubator.foreign.ValueLayout;


 33 import jdk.internal.foreign.MemoryAddressImpl;
 34 import sun.security.action.GetPropertyAction;
 35 
 36 import java.lang.invoke.MethodHandle;
 37 import java.lang.invoke.MethodHandles;
 38 import java.lang.invoke.MethodType;
 39 import java.lang.invoke.VarHandle;
 40 import java.util.Arrays;
 41 import java.util.List;
 42 import java.util.Map;
 43 import java.util.Objects;
 44 import java.util.stream.Stream;
 45 
 46 import static java.lang.invoke.MethodHandles.dropArguments;
 47 import static java.lang.invoke.MethodHandles.exactInvoker;
 48 import static java.lang.invoke.MethodHandles.filterReturnValue;
 49 import static java.lang.invoke.MethodHandles.identity;
 50 import static java.lang.invoke.MethodHandles.insertArguments;
 51 import static java.lang.invoke.MethodHandles.lookup;
 52 import static java.lang.invoke.MethodType.methodType;
 53 import static jdk.internal.foreign.abi.SharedUtils.mergeArguments;
 54 import static sun.security.action.GetBooleanAction.privilegedGetProperty;
 55 
 56 /**
 57  * This class implements upcall invocation from native code through a so called 'universal adapter'. A universal upcall adapter
 58  * takes an array of storage pointers, which describes the state of the CPU at the time of the upcall. This can be used
 59  * by the Java code to fetch the upcall arguments and to store the results to the desired location, as per system ABI.
 60  */
 61 public class ProgrammableUpcallHandler {
 62     private static final boolean DEBUG =
 63         privilegedGetProperty("jdk.internal.foreign.ProgrammableUpcallHandler.DEBUG");
 64     private static final boolean USE_SPEC = Boolean.parseBoolean(
 65         GetPropertyAction.privilegedGetProperty("jdk.internal.foreign.ProgrammableUpcallHandler.USE_SPEC", "true"));
 66     private static final boolean USE_INTRINSICS = Boolean.parseBoolean(
 67         GetPropertyAction.privilegedGetProperty("jdk.internal.foreign.ProgrammableUpcallHandler.USE_INTRINSICS", "true"));
 68 
 69     private static final VarHandle VH_LONG = ValueLayout.JAVA_LONG.varHandle();


 70 
 71     private static final MethodHandle MH_invokeMoves;
 72     private static final MethodHandle MH_invokeInterpBindings;
 73 
 74     static {
 75         try {
 76             MethodHandles.Lookup lookup = lookup();
 77             MH_invokeMoves = lookup.findStatic(ProgrammableUpcallHandler.class, "invokeMoves",
 78                     methodType(void.class, MemoryAddress.class, MethodHandle.class,
 79                                Binding.VMLoad[].class, Binding.VMStore[].class, ABIDescriptor.class, BufferLayout.class));
 80             MH_invokeInterpBindings = lookup.findStatic(ProgrammableUpcallHandler.class, "invokeInterpBindings",
 81                     methodType(Object.class, Object[].class, MethodHandle.class, Map.class, Map.class,
 82                             CallingSequence.class, long.class));
 83         } catch (ReflectiveOperationException e) {
 84             throw new InternalError(e);
 85         }
 86     }
 87 
 88     public static NativeSymbol make(ABIDescriptor abi, MethodHandle target, CallingSequence callingSequence, ResourceScope scope) {
 89         Binding.VMLoad[] argMoves = argMoveBindings(callingSequence);
 90         Binding.VMStore[] retMoves = retMoveBindings(callingSequence);
 91 
 92         boolean isSimple = !(retMoves.length > 1);
 93 
 94         Class<?> llReturn = !isSimple
 95             ? Object[].class
 96             : retMoves.length == 1
 97                 ? retMoves[0].type()
 98                 : void.class;
 99         Class<?>[] llParams = Arrays.stream(argMoves).map(Binding.Move::type).toArray(Class<?>[]::new);
100         MethodType llType = MethodType.methodType(llReturn, llParams);
101 
102         MethodHandle doBindings;
103         long bufferCopySize = SharedUtils.bufferCopySize(callingSequence);
104         if (USE_SPEC && isSimple) {
105             doBindings = specializedBindingHandle(target, callingSequence, llReturn, bufferCopySize);
106             assert doBindings.type() == llType;
107         } else {
108             Map<VMStorage, Integer> argIndices = SharedUtils.indexMap(argMoves);
109             Map<VMStorage, Integer> retIndices = SharedUtils.indexMap(retMoves);
110             target = target.asSpreader(Object[].class, callingSequence.methodType().parameterCount());
111             doBindings = insertArguments(MH_invokeInterpBindings, 1, target, argIndices, retIndices, callingSequence,
112                     bufferCopySize);
113             doBindings = doBindings.asCollector(Object[].class, llType.parameterCount());
114             doBindings = doBindings.asType(llType);
115         }
116 
117         long entryPoint;
118         if (USE_INTRINSICS && isSimple && supportsOptimizedUpcalls()) {



119             checkPrimitive(doBindings.type());
120             doBindings = insertArguments(exactInvoker(doBindings.type()), 0, doBindings);
121             VMStorage[] args = Arrays.stream(argMoves).map(Binding.Move::storage).toArray(VMStorage[]::new);
122             VMStorage[] rets = Arrays.stream(retMoves).map(Binding.Move::storage).toArray(VMStorage[]::new);
123             CallRegs conv = new CallRegs(args, rets);
124             entryPoint = allocateOptimizedUpcallStub(doBindings, abi, conv);
125         } else {
126             BufferLayout layout = BufferLayout.of(abi);
127             MethodHandle doBindingsErased = doBindings.asSpreader(Object[].class, doBindings.type().parameterCount());
128             MethodHandle invokeMoves = insertArguments(MH_invokeMoves, 1, doBindingsErased, argMoves, retMoves, abi, layout);
129             entryPoint = allocateUpcallStub(invokeMoves, abi, layout);
130         }
131         return UpcallStubs.makeUpcall(entryPoint, scope);
132     }
133 
134     private static void checkPrimitive(MethodType type) {
135         if (!type.returnType().isPrimitive()
136                 || type.parameterList().stream().anyMatch(p -> !p.isPrimitive()))
137             throw new IllegalArgumentException("MethodHandle type must be primitive: " + type);
138     }
139 
140     private static Stream<Binding.VMLoad> argMoveBindingsStream(CallingSequence callingSequence) {
141         return callingSequence.argumentBindings()
142                 .filter(Binding.VMLoad.class::isInstance)
143                 .map(Binding.VMLoad.class::cast);
144     }
145 
146     private static Binding.VMLoad[] argMoveBindings(CallingSequence callingSequence) {
147         return argMoveBindingsStream(callingSequence)
148                 .toArray(Binding.VMLoad[]::new);
149     }
150 
151     private static Binding.VMStore[] retMoveBindings(CallingSequence callingSequence) {
< prev index next >