< prev index next >

src/java.base/share/classes/jdk/internal/foreign/abi/UniversalNativeInvoker.java

Print this page


   1 /*
   2  * Copyright (c) 2018, 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.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 package jdk.internal.foreign.abi;
  24 
  25 import jdk.internal.foreign.ScopeImpl;
  26 import jdk.internal.foreign.memory.BoundedPointer;
  27 

  28 import java.foreign.NativeMethodType;
  29 import java.foreign.NativeTypes;
  30 import java.foreign.Scope;
  31 import java.foreign.memory.LayoutType;
  32 import java.foreign.memory.Pointer;
  33 import java.lang.invoke.MethodHandle;
  34 import java.lang.invoke.MethodHandles;
  35 import java.lang.invoke.MethodType;
  36 import java.util.List;
  37 import java.util.function.Function;
  38 
  39 import static sun.security.action.GetBooleanAction.privilegedGetProperty;
  40 
  41 /**
  42  * This class implements native call invocation through a so called 'universal adapter'. A universal adapter takes
  43  * an array of longs together with a call 'recipe', which is used to move the arguments in the right places as
  44  * expected by the system ABI.
  45  */
  46 public abstract class UniversalNativeInvoker {
  47     private static final boolean DEBUG =
  48         privilegedGetProperty("jdk.internal.foreign.NativeInvoker.DEBUG");
  49 
  50     // Unbound MH for the invoke() method
  51     private static final MethodHandle INVOKE_MH;
  52     private static final MethodHandle INVOKE_NATIVE_MH;
  53 
  54     static {
  55         try {
  56             MethodType INVOKE_NATIVE_MT = MethodType.methodType(void.class, long[].class, long[].class, long[].class, long.class);
  57             INVOKE_NATIVE_MH = MethodHandles.lookup().findStatic(UniversalNativeInvoker.class, "invokeNative", INVOKE_NATIVE_MT);
  58             INVOKE_MH = MethodHandles.lookup().findVirtual(UniversalNativeInvoker.class, "invoke", MethodType.methodType(Object.class, Object[].class));
  59         } catch (ReflectiveOperationException e) {
  60             throw new RuntimeException(e);
  61         }
  62     }
  63 
  64     private final ShuffleRecipe shuffleRecipe;
  65     private final NativeMethodType nmt;
  66     private final CallingSequence callingSequence;
  67     private final long addr;
  68     private final String methodName;

  69 
  70     protected UniversalNativeInvoker(long addr, String methodName, CallingSequence callingSequence, NativeMethodType nmt) {
  71         this.addr = addr;
  72         this.methodName = methodName;


  73         this.callingSequence = callingSequence;
  74         this.nmt = nmt;
  75         this.shuffleRecipe = ShuffleRecipe.make(callingSequence);
  76     }
  77 
  78     public MethodHandle getBoundMethodHandle() {
  79         return INVOKE_MH.bindTo(this).asCollector(Object[].class, nmt.parameterCount())
  80                 .asType(nmt.methodType());
  81     }
  82 
  83     Object invoke(Object[] args) throws Throwable {
  84         boolean isVoid = nmt.returnType() == NativeTypes.VOID;
  85         int nValues = shuffleRecipe.getNoofArgumentPulls();
  86         long[] values = new long[nValues];
  87         Pointer<Long> argsPtr = nValues > 0 ?
  88                 BoundedPointer.fromArray(NativeTypes.UINT64, values) :
  89                 Pointer.ofNull();
  90 
  91         for (int i = 0; i < args.length; i++) {
  92             Object arg = args[i];
  93             unboxValue(arg, nmt.parameterType(i), b -> argsPtr.offset(callingSequence.argumentStorageOffset(b)),
  94                     callingSequence.getArgumentBindings(i));
  95         }
  96 
  97         final Pointer<?> retPtr;
  98         long[] returnValues = new long[shuffleRecipe.getNoofReturnPulls()];
  99         if (callingSequence.returnsInMemory()) {
 100             // FIXME (STRUCT-LIFECYCLE):
 101             // Leak the allocated structs for now until the life cycle has been figured out
 102             Scope scope = Scope.globalScope().fork();
 103             retPtr = ((ScopeImpl)scope).allocate(nmt.returnType(), 8);
 104             unboxValue(retPtr, NativeTypes.UINT64.pointer(), b -> argsPtr.offset(callingSequence.argumentStorageOffset(b)),
 105                     callingSequence.getReturnBindings());
 106         } else if (!isVoid && returnValues.length != 0) {
 107             retPtr = BoundedPointer.fromArray(NativeTypes.UINT64, returnValues);
 108         } else {
 109             retPtr = Pointer.ofNull();
 110         }
 111 
 112         if (DEBUG) {
 113             System.err.println("Invoking method " + methodName + " with " + values.length + " argument values");
 114             for (int i = 0; i < values.length; i++) {
 115                 System.err.println("value[" + i + "] = 0x" + Long.toHexString(values[i]));
 116             }
 117         }
 118 
 119         INVOKE_NATIVE_MH.invokeExact(values, returnValues, shuffleRecipe.getRecipe(), addr);
 120 
 121         if (DEBUG) {
 122             System.err.println("Returned from method " + methodName + " with " + returnValues.length + " return values");
 123             System.err.println("structPtr = 0x" + Long.toHexString(retPtr.addr()));
 124             for (int i = 0; i < returnValues.length; i++) {
 125                 System.err.println("returnValues[" + i + "] = 0x" + Long.toHexString(returnValues[i]));
 126             }
 127         }
 128 
 129         if (isVoid) {
 130             return null;
 131         } else if (!callingSequence.returnsInMemory()) {
 132             return boxValue(nmt.returnType(), b -> retPtr.offset(callingSequence.returnStorageOffset(b)), callingSequence.getReturnBindings());
 133         } else {
 134             return retPtr.get();
 135         }
 136     }
 137 
 138     public abstract void unboxValue(Object o, LayoutType<?> type, Function<ArgumentBinding,
 139                 Pointer<?>> dstPtrFunc, List<ArgumentBinding> bindings) throws Throwable;
 140 
 141     public abstract Object boxValue(LayoutType<?> type, Function<ArgumentBinding,
 142             Pointer<?>> srcPtrFunc, List<ArgumentBinding> bindings) throws IllegalAccessException;
 143 
 144     //natives
 145 
 146     static native void invokeNative(long[] args, long[] rets, long[] recipe, long addr);
 147 
 148     private static native void registerNatives();
 149     static {
 150         registerNatives();
 151     }
 152 }
   1 /*
   2  * Copyright (c) 2018, 2019, 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.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 package jdk.internal.foreign.abi;
  24 
  25 import jdk.internal.foreign.ScopeImpl;
  26 import jdk.internal.foreign.memory.BoundedPointer;
  27 
  28 import java.foreign.Library;
  29 import java.foreign.NativeMethodType;
  30 import java.foreign.NativeTypes;
  31 import java.foreign.Scope;

  32 import java.foreign.memory.Pointer;
  33 import java.lang.invoke.MethodHandle;
  34 import java.lang.invoke.MethodHandles;
  35 import java.lang.invoke.MethodType;
  36 import java.util.List;

  37 
  38 import static sun.security.action.GetBooleanAction.privilegedGetProperty;
  39 
  40 /**
  41  * This class implements native call invocation through a so called 'universal adapter'. A universal adapter takes
  42  * an array of longs together with a call 'recipe', which is used to move the arguments in the right places as
  43  * expected by the system ABI.
  44  */
  45 public class UniversalNativeInvoker {
  46     private static final boolean DEBUG =
  47         privilegedGetProperty("jdk.internal.foreign.NativeInvoker.DEBUG");
  48 
  49     // Unbound MH for the invoke() method
  50     private static final MethodHandle INVOKE_MH;
  51     private static final MethodHandle INVOKE_NATIVE_MH;
  52 
  53     static {
  54         try {
  55             MethodType INVOKE_NATIVE_MT = MethodType.methodType(void.class, long[].class, long[].class, long[].class, long.class);
  56             INVOKE_NATIVE_MH = MethodHandles.lookup().findStatic(UniversalNativeInvoker.class, "invokeNative", INVOKE_NATIVE_MT);
  57             INVOKE_MH = MethodHandles.lookup().findVirtual(UniversalNativeInvoker.class, "invoke", MethodType.methodType(Object.class, Object[].class));
  58         } catch (ReflectiveOperationException e) {
  59             throw new RuntimeException(e);
  60         }
  61     }
  62 
  63     private final ShuffleRecipe shuffleRecipe;
  64     private final NativeMethodType nmt;
  65     private final CallingSequence callingSequence;
  66     private final long addr;
  67     private final String methodName;
  68     private final UniversalAdapter adapter;
  69 
  70     public UniversalNativeInvoker(Library.Symbol symbol, CallingSequence callingSequence, NativeMethodType nmt,
  71                                      UniversalAdapter adapter) throws IllegalAccessException {
  72         this.adapter = adapter;
  73         this.addr = symbol.getAddress().addr();
  74         this.methodName = symbol.getName();
  75         this.callingSequence = callingSequence;
  76         this.nmt = nmt;
  77         this.shuffleRecipe = ShuffleRecipe.make(callingSequence);
  78     }
  79 
  80     public MethodHandle getBoundMethodHandle() {
  81         return INVOKE_MH.bindTo(this).asCollector(Object[].class, nmt.parameterCount())
  82                 .asType(nmt.methodType());
  83     }
  84 
  85     Object invoke(Object[] args) throws Throwable {
  86         boolean isVoid = nmt.returnType() == NativeTypes.VOID;
  87         int nValues = shuffleRecipe.getNoofArgumentPulls();
  88         long[] values = new long[nValues];
  89         Pointer<Long> argsPtr = nValues > 0 ?
  90                 BoundedPointer.fromArray(NativeTypes.UINT64, values) :
  91                 Pointer.ofNull();
  92 
  93         for (int i = 0; i < args.length; i++) {
  94             Object arg = args[i];
  95             adapter.unboxValue(arg, nmt.parameterType(i), b -> shuffleRecipe.offset(argsPtr, b),
  96                     callingSequence.argumentBindings(i));
  97         }
  98 
  99         final Pointer<?> retPtr;
 100         long[] returnValues = new long[shuffleRecipe.getNoofReturnPulls()];
 101         if (callingSequence.returnsInMemory()) {
 102             // FIXME (STRUCT-LIFECYCLE):
 103             // Leak the allocated structs for now until the life cycle has been figured out
 104             Scope scope = Scope.globalScope().fork();
 105             retPtr = ((ScopeImpl)scope).allocate(nmt.returnType(), 8);
 106             adapter.unboxValue(retPtr, NativeTypes.UINT64.pointer(), b -> shuffleRecipe.offset(argsPtr, b),
 107                     List.of(callingSequence.returnInMemoryBinding()));
 108         } else if (!isVoid && returnValues.length != 0) {
 109             retPtr = BoundedPointer.fromArray(NativeTypes.UINT64, returnValues);
 110         } else {
 111             retPtr = Pointer.ofNull();
 112         }
 113 
 114         if (DEBUG) {
 115             System.err.println("Invoking method " + methodName + " with " + values.length + " argument values");
 116             for (int i = 0; i < values.length; i++) {
 117                 System.err.println("value[" + i + "] = 0x" + Long.toHexString(values[i]));
 118             }
 119         }
 120 
 121         INVOKE_NATIVE_MH.invokeExact(values, returnValues, shuffleRecipe.getRecipe(), addr);
 122 
 123         if (DEBUG) {
 124             System.err.println("Returned from method " + methodName + " with " + returnValues.length + " return values");
 125             System.err.println("structPtr = 0x" + Long.toHexString(retPtr.addr()));
 126             for (int i = 0; i < returnValues.length; i++) {
 127                 System.err.println("returnValues[" + i + "] = 0x" + Long.toHexString(returnValues[i]));
 128             }
 129         }
 130 
 131         if (isVoid) {
 132             return null;
 133         } else if (!callingSequence.returnsInMemory()) {
 134             return adapter.boxValue(nmt.returnType(), b -> shuffleRecipe.offset(retPtr, b), callingSequence.returnBindings());
 135         } else {
 136             return retPtr.get();
 137         }
 138     }






 139 
 140     //natives
 141 
 142     static native void invokeNative(long[] args, long[] rets, long[] recipe, long addr);
 143 
 144     private static native void registerNatives();
 145     static {
 146         registerNatives();
 147     }
 148 }
< prev index next >