< prev index next >

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

Print this page




   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 
  24 package jdk.internal.foreign.abi;
  25 
  26 import java.foreign.Library;
  27 import java.foreign.NativeMethodType;
  28 import java.foreign.NativeTypes;
  29 import java.foreign.Scope;
  30 import java.foreign.memory.LayoutType;
  31 import java.foreign.memory.Pointer;
  32 import java.lang.invoke.MethodHandle;
  33 import java.util.Arrays;
  34 import java.util.List;
  35 import java.util.function.Function;
  36 
  37 import jdk.internal.foreign.ScopeImpl;
  38 import jdk.internal.foreign.Util;
  39 import jdk.internal.foreign.abi.x64.SharedConstants;
  40 import jdk.internal.foreign.memory.MemoryBoundInfo;
  41 import jdk.internal.foreign.memory.BoundedPointer;
  42 import jdk.internal.vm.annotation.Stable;
  43 
  44 import static sun.security.action.GetBooleanAction.privilegedGetProperty;
  45 
  46 /**
  47  * This class implements upcall invocation from native code through a so called 'universal adapter'. A universal upcall adapter
  48  * takes an array of storage pointers, which describes the state of the CPU at the time of the upcall. This can be used
  49  * by the Java code to fetch the upcall arguments and to store the results to the desired location, as per system ABI.
  50  */
  51 public abstract class UniversalUpcallHandler implements Library.Symbol {
  52 
  53     private static final boolean DEBUG =
  54         privilegedGetProperty("jdk.internal.foreign.UpcallHandler.DEBUG");
  55 
  56     @Stable
  57     private final MethodHandle mh;
  58     private final NativeMethodType nmt;
  59     private final CallingSequence callingSequence;
  60     private final Pointer<?> entryPoint;

  61 
  62     protected UniversalUpcallHandler(MethodHandle target, CallingSequence callingSequence, NativeMethodType nmt) {


  63         mh = target.asSpreader(Object[].class, nmt.parameterCount());
  64         this.nmt = nmt;
  65         this.callingSequence = callingSequence;
  66         this.entryPoint = BoundedPointer.createNativeVoidPointer(allocateUpcallStub());
  67     }
  68 
  69     @Override
  70     public String getName() {
  71         return toString();
  72     }
  73 
  74     @Override
  75     public Pointer<?> getAddress() {
  76         return entryPoint;
  77     }
  78 
  79     public static void invoke(UniversalUpcallHandler handler, long integers, long vectors, long stack, long integerReturn, long vectorReturn, long x87Return) {
  80         UpcallContext context = handler.new UpcallContext(integers, vectors, stack, integerReturn, vectorReturn, x87Return);
  81         handler.invoke(context);
  82     }
  83 
  84     class UpcallContext {
  85 
  86         private final Pointer<Long> integers;
  87         private final Pointer<Long> vectors;
  88         private final Pointer<Long> stack;
  89         private final Pointer<Long> integerReturns;
  90         private final Pointer<Long> vectorReturns;
  91         private final Pointer<Long> x87Returns;
  92 
  93         UpcallContext(long integers, long vectors, long stack, long integerReturn, long vectorReturn, long x87Returns) {
  94             this.integers = BoundedPointer.createRegisterPointer(NativeTypes.UINT64, integers, false);
  95             this.vectors = BoundedPointer.createRegisterPointer(NativeTypes.UINT64, vectors, false);
  96             this.stack = BoundedPointer.createRegisterPointer(NativeTypes.UINT64, stack, false);
  97             this.integerReturns = BoundedPointer.createRegisterPointer(NativeTypes.UINT64, integerReturn, true);
  98             this.vectorReturns = BoundedPointer.createRegisterPointer(NativeTypes.UINT64, vectorReturn, true);
  99             this.x87Returns = BoundedPointer.createRegisterPointer(NativeTypes.UINT64, x87Returns, true);
 100         }
 101 
 102         Pointer<Long> getPtr(ArgumentBinding binding) {
 103             Storage storage = binding.getStorage();
 104             switch (storage.getStorageClass()) {
 105             case INTEGER_ARGUMENT_REGISTER:
 106                 return integers.offset(storage.getStorageIndex());
 107             case VECTOR_ARGUMENT_REGISTER:
 108                 return vectors.offset(storage.getStorageIndex() * SharedConstants.VECTOR_REGISTER_SIZE / 8);
 109             case STACK_ARGUMENT_SLOT:
 110                 return stack.offset(storage.getStorageIndex());
 111             case INTEGER_RETURN_REGISTER:
 112                 return integerReturns.offset(storage.getStorageIndex());
 113             case VECTOR_RETURN_REGISTER:
 114                 return vectorReturns.offset(storage.getStorageIndex() * SharedConstants.VECTOR_REGISTER_SIZE / 8);
 115             case X87_RETURN_REGISTER:
 116                 return x87Returns.offset(storage.getStorageIndex() * SharedConstants.X87_REGISTER_SIZE / 8);
 117             default:
 118                 throw new Error("Unhandled storage: " + storage);
 119             }
 120         }
 121 
 122         @SuppressWarnings("unchecked")
 123         Pointer<Object> inMemoryPtr() {
 124             assert callingSequence.returnsInMemory();
 125             Pointer<Long> res = getPtr(callingSequence.getReturnBindings().get(0));
 126             long structAddr = res.get();
 127             long size = Util.alignUp(nmt.returnType().bytesSize(), 8);
 128             return new BoundedPointer<Object>((LayoutType)nmt.returnType(), ScopeImpl.UNCHECKED, Pointer.AccessMode.READ_WRITE,
 129                     MemoryBoundInfo.ofNative(structAddr, size));
 130         }
 131 
 132         void setReturnPtr(long ptr) {
 133             assert callingSequence.returnsInMemory();
 134             integerReturns.set(ptr);
 135         }
 136 
 137         public String asString() {
 138             StringBuilder result = new StringBuilder();
 139             result.append("UpcallContext:\n");
 140             if (callingSequence.returnsInMemory()) {
 141                 result.append("In memory pointer:\n".indent(2));
 142                 result.append(inMemoryPtr().toString().indent(4));
 143             }
 144             for (StorageClass cls : StorageClass.values()) {
 145                 result.append((cls + "\n").indent(2));
 146                 for (ArgumentBinding binding : callingSequence.getBindings(cls)) {
 147                     BoundedPointer<?> argPtr = (BoundedPointer<?>) getPtr(binding);
 148                     result.append(argPtr.dump((int) binding.getStorage().getSize()).indent(4));
 149                 }
 150             }
 151             return result.toString();
 152         }
 153     }
 154 
 155     private void invoke(UpcallContext context) {
 156         try {
 157             // FIXME: Handle varargs upcalls here
 158             if (DEBUG) {
 159                 System.err.println("=== UpcallHandler.invoke ===");
 160                 System.err.println(callingSequence.asString());
 161                 System.err.println(context.asString());
 162             }
 163 
 164             Object[] args = new Object[nmt.parameterCount()];
 165             for (int i = 0 ; i < nmt.parameterCount() ; i++) {
 166                 args[i] = boxValue(nmt.parameterType(i), context::getPtr, callingSequence.getArgumentBindings(i));
 167             }
 168 
 169             if (DEBUG) {
 170                 System.err.println("Java arguments:");
 171                 System.err.println(Arrays.toString(args).indent(2));
 172             }
 173 
 174             Object o = mh.invoke(args);
 175 
 176             if (DEBUG) {
 177                 System.err.println("Java return:");
 178                 System.err.println(o.toString().indent(2));
 179             }
 180 
 181             if (mh.type().returnType() != void.class) {
 182                 if (!callingSequence.returnsInMemory()) {
 183                     unboxValue(o, nmt.returnType(), context::getPtr,
 184                             callingSequence.getReturnBindings());
 185                 } else {
 186                     Pointer<Object> inMemPtr = context.inMemoryPtr();
 187                     inMemPtr.set(o);
 188                     context.setReturnPtr(inMemPtr.addr()); // Write to RAX
 189                 }
 190             }
 191 
 192             if (DEBUG) {
 193                 System.err.println("Returning:");
 194                 System.err.println(context.asString().indent(2));
 195             }
 196         } catch (Throwable t) {
 197             throw new IllegalStateException(t);
 198         }
 199     }
 200 
 201     public abstract void unboxValue(Object o, LayoutType<?> type, Function<ArgumentBinding,
 202                 Pointer<?>> dstPtrFunc, List<ArgumentBinding> bindings) throws Throwable;
 203 
 204     public abstract Object boxValue(LayoutType<?> type, Function<ArgumentBinding,
 205             Pointer<?>> srcPtrFunc, List<ArgumentBinding> bindings) throws IllegalAccessException;
 206 
 207     public native long allocateUpcallStub();
 208 
 209     private static native void registerNatives();
 210     static {
 211         registerNatives();
 212     }
 213 }


   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 
  24 package jdk.internal.foreign.abi;
  25 
  26 import java.foreign.Library;
  27 import java.foreign.NativeMethodType;
  28 import java.foreign.NativeTypes;

  29 import java.foreign.memory.LayoutType;
  30 import java.foreign.memory.Pointer;
  31 import java.lang.invoke.MethodHandle;
  32 import java.util.Arrays;


  33 
  34 import jdk.internal.foreign.ScopeImpl;
  35 import jdk.internal.foreign.Util;
  36 import jdk.internal.foreign.abi.x64.SharedUtils;
  37 import jdk.internal.foreign.memory.MemoryBoundInfo;
  38 import jdk.internal.foreign.memory.BoundedPointer;
  39 import jdk.internal.vm.annotation.Stable;
  40 
  41 import static sun.security.action.GetBooleanAction.privilegedGetProperty;
  42 
  43 /**
  44  * This class implements upcall invocation from native code through a so called 'universal adapter'. A universal upcall adapter
  45  * takes an array of storage pointers, which describes the state of the CPU at the time of the upcall. This can be used
  46  * by the Java code to fetch the upcall arguments and to store the results to the desired location, as per system ABI.
  47  */
  48 public class UniversalUpcallHandler implements Library.Symbol {
  49 
  50     private static final boolean DEBUG =
  51         privilegedGetProperty("jdk.internal.foreign.UpcallHandler.DEBUG");
  52 
  53     @Stable
  54     private final MethodHandle mh;
  55     private final NativeMethodType nmt;
  56     private final CallingSequence callingSequence;
  57     private final Pointer<?> entryPoint;
  58     private final UniversalAdapter adapter;
  59 
  60     public UniversalUpcallHandler(MethodHandle target, CallingSequence callingSequence, NativeMethodType nmt,
  61                                      UniversalAdapter adapter) {
  62         this.adapter = adapter;
  63         mh = target.asSpreader(Object[].class, nmt.parameterCount());
  64         this.nmt = nmt;
  65         this.callingSequence = callingSequence;
  66         this.entryPoint = BoundedPointer.createNativeVoidPointer(allocateUpcallStub());
  67     }
  68 
  69     @Override
  70     public String getName() {
  71         return toString();
  72     }
  73 
  74     @Override
  75     public Pointer<?> getAddress() {
  76         return entryPoint;
  77     }
  78 
  79     public static void invoke(UniversalUpcallHandler handler, long integers, long vectors, long stack, long integerReturn, long vectorReturn, long x87Return) {
  80         UpcallContext context = handler.new UpcallContext(integers, vectors, stack, integerReturn, vectorReturn, x87Return);
  81         handler.invoke(context);
  82     }
  83 
  84     class UpcallContext {
  85 
  86         private final Pointer<Long> integers;
  87         private final Pointer<Long> vectors;
  88         private final Pointer<Long> stack;
  89         private final Pointer<Long> integerReturns;
  90         private final Pointer<Long> vectorReturns;
  91         private final Pointer<Long> x87Returns;
  92 
  93         UpcallContext(long integers, long vectors, long stack, long integerReturn, long vectorReturn, long x87Returns) {
  94             this.integers = BoundedPointer.createRegisterPointer(NativeTypes.UINT64, integers, false);
  95             this.vectors = BoundedPointer.createRegisterPointer(NativeTypes.UINT64, vectors, false);
  96             this.stack = BoundedPointer.createRegisterPointer(NativeTypes.UINT64, stack, false);
  97             this.integerReturns = BoundedPointer.createRegisterPointer(NativeTypes.UINT64, integerReturn, true);
  98             this.vectorReturns = BoundedPointer.createRegisterPointer(NativeTypes.UINT64, vectorReturn, true);
  99             this.x87Returns = BoundedPointer.createRegisterPointer(NativeTypes.UINT64, x87Returns, true);
 100         }
 101 
 102         Pointer<Long> getPtr(ArgumentBinding binding) {
 103             Storage storage = binding.storage();
 104             switch (storage.getStorageClass()) {
 105             case INTEGER_ARGUMENT_REGISTER:
 106                 return integers.offset(storage.getStorageIndex());
 107             case VECTOR_ARGUMENT_REGISTER:
 108                 return vectors.offset(storage.getStorageIndex() * SharedUtils.VECTOR_REGISTER_SIZE / 8);
 109             case STACK_ARGUMENT_SLOT:
 110                 return stack.offset(storage.getStorageIndex());
 111             case INTEGER_RETURN_REGISTER:
 112                 return integerReturns.offset(storage.getStorageIndex());
 113             case VECTOR_RETURN_REGISTER:
 114                 return vectorReturns.offset(storage.getStorageIndex() * SharedUtils.VECTOR_REGISTER_SIZE / 8);
 115             case X87_RETURN_REGISTER:
 116                 return x87Returns.offset(storage.getStorageIndex() * SharedUtils.X87_REGISTER_SIZE / 8);
 117             default:
 118                 throw new Error("Unhandled storage: " + storage);
 119             }
 120         }
 121 
 122         @SuppressWarnings("unchecked")
 123         Pointer<Object> inMemoryPtr() {
 124             assert callingSequence.returnsInMemory();
 125             Pointer<Long> res = getPtr(callingSequence.returnInMemoryBinding());
 126             long structAddr = res.get();
 127             long size = Util.alignUp(nmt.returnType().bytesSize(), 8);
 128             return new BoundedPointer<Object>((LayoutType)nmt.returnType(), ScopeImpl.UNCHECKED, Pointer.AccessMode.READ_WRITE,
 129                     MemoryBoundInfo.ofNative(structAddr, size));
 130         }
 131 
 132         void setReturnPtr(long ptr) {
 133             assert callingSequence.returnsInMemory();
 134             integerReturns.set(ptr);
 135         }
 136 
 137         public String asString() {
 138             StringBuilder result = new StringBuilder();
 139             result.append("UpcallContext:\n");
 140             if (callingSequence.returnsInMemory()) {
 141                 result.append("In memory pointer:\n".indent(2));
 142                 result.append(inMemoryPtr().toString().indent(4));
 143             }
 144             for (StorageClass cls : StorageClass.values()) {
 145                 result.append((cls + "\n").indent(2));
 146                 for (ArgumentBinding binding : callingSequence.bindings(cls)) {
 147                     BoundedPointer<?> argPtr = (BoundedPointer<?>) getPtr(binding);
 148                     result.append(argPtr.dump((int) binding.storage().getSize()).indent(4));
 149                 }
 150             }
 151             return result.toString();
 152         }
 153     }
 154 
 155     private void invoke(UpcallContext context) {
 156         try {
 157             // FIXME: Handle varargs upcalls here
 158             if (DEBUG) {
 159                 System.err.println("=== UpcallHandler.invoke ===");
 160                 System.err.println(callingSequence.asString());
 161                 System.err.println(context.asString());
 162             }
 163 
 164             Object[] args = new Object[nmt.parameterCount()];
 165             for (int i = 0 ; i < nmt.parameterCount() ; i++) {
 166                 args[i] = adapter.boxValue(nmt.parameterType(i), context::getPtr, callingSequence.argumentBindings(i));
 167             }
 168 
 169             if (DEBUG) {
 170                 System.err.println("Java arguments:");
 171                 System.err.println(Arrays.toString(args).indent(2));
 172             }
 173 
 174             Object o = mh.invoke(args);
 175 
 176             if (DEBUG) {
 177                 System.err.println("Java return:");
 178                 System.err.println(o.toString().indent(2));
 179             }
 180 
 181             if (mh.type().returnType() != void.class) {
 182                 if (!callingSequence.returnsInMemory()) {
 183                     adapter.unboxValue(o, nmt.returnType(), context::getPtr,
 184                             callingSequence.returnBindings());
 185                 } else {
 186                     Pointer<Object> inMemPtr = context.inMemoryPtr();
 187                     inMemPtr.set(o);
 188                     context.setReturnPtr(inMemPtr.addr()); // Write to RAX
 189                 }
 190             }
 191 
 192             if (DEBUG) {
 193                 System.err.println("Returning:");
 194                 System.err.println(context.asString().indent(2));
 195             }
 196         } catch (Throwable t) {
 197             throw new IllegalStateException(t);
 198         }
 199     }






 200 
 201     public native long allocateUpcallStub();
 202 
 203     private static native void registerNatives();
 204     static {
 205         registerNatives();
 206     }
 207 }
< prev index next >