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 24 package jdk.internal.foreign.abi; 25 26 import jdk.incubator.foreign.MemoryAddress; 27 import jdk.incubator.foreign.MemoryHandles; 28 import jdk.internal.foreign.MemoryAddressImpl; 29 import jdk.internal.foreign.Utils; 30 import jdk.internal.vm.annotation.Stable; 31 32 import java.lang.invoke.MethodHandle; 33 import java.lang.invoke.MethodType; 34 import java.lang.invoke.VarHandle; 35 import java.nio.ByteOrder; 36 import java.util.ArrayList; 37 import java.util.Arrays; 38 import java.util.Objects; 39 40 import static sun.security.action.GetBooleanAction.privilegedGetProperty; 41 42 /** 43 * This class implements upcall invocation from native code through a so called 'universal adapter'. A universal upcall adapter 44 * takes an array of storage pointers, which describes the state of the CPU at the time of the upcall. This can be used 45 * by the Java code to fetch the upcall arguments and to store the results to the desired location, as per system ABI. 46 */ 47 public class ProgrammableUpcallHandler implements UpcallHandler { 48 49 private static final boolean DEBUG = 50 privilegedGetProperty("jdk.internal.foreign.ProgrammableUpcallHandler.DEBUG"); 51 52 private static final VarHandle VH_LONG = MemoryHandles.varHandle(long.class, ByteOrder.nativeOrder()); 53 54 @Stable 55 private final MethodHandle mh; 56 private final MethodType type; 57 private final CallingSequence callingSequence; 58 private final long entryPoint; 59 60 private final ABIDescriptor abi; 61 private final BufferLayout layout; 62 63 public ProgrammableUpcallHandler(ABIDescriptor abi, MethodHandle target, CallingSequence callingSequence) { 64 this.abi = abi; 65 this.layout = BufferLayout.of(abi); 66 this.type = callingSequence.methodType(); 67 this.callingSequence = callingSequence; 68 this.mh = target.asSpreader(Object[].class, callingSequence.methodType().parameterCount()); 69 this.entryPoint = allocateUpcallStub(abi, layout); 70 } 71 72 @Override 73 public long entryPoint() { 74 return entryPoint; 75 } 76 77 public static void invoke(ProgrammableUpcallHandler handler, long address) { 78 handler.invoke(MemoryAddress.ofLong(address)); 79 } 80 81 private void invoke(MemoryAddress buffer) { 82 try { 83 if (DEBUG) { 84 System.err.println("Buffer state before:"); 85 layout.dump(abi.arch, buffer, System.err); 86 } 87 88 MemoryAddress bufferBase = MemoryAddressImpl.ofLongUnchecked(buffer.toRawLongValue(), layout.size); 89 MemoryAddress stackArgsBase = MemoryAddressImpl.ofLongUnchecked((long)VH_LONG.get(buffer.rebase(bufferBase.segment()).addOffset(layout.stack_args))); 90 Object[] args = new Object[type.parameterCount()]; 91 for (int i = 0 ; i < type.parameterCount() ; i++) { 92 args[i] = BindingInterpreter.box(callingSequence.argumentBindings(i), 93 (storage, type) -> { 94 MemoryAddress ptr = abi.arch.isStackType(storage.type()) 95 ? stackArgsBase.addOffset(storage.index() * abi.arch.typeSize(abi.arch.stackType())) 96 : bufferBase.addOffset(layout.argOffset(storage)); 97 return SharedUtils.read(ptr, type); 98 }); 99 } 100 101 if (DEBUG) { 102 System.err.println("Java arguments:"); 103 System.err.println(Arrays.toString(args).indent(2)); 104 } 105 106 Object o = mh.invoke(args); 107 108 if (DEBUG) { 109 System.err.println("Java return:"); 110 System.err.println(Objects.toString(o).indent(2)); 111 } 112 113 if (mh.type().returnType() != void.class) { 114 BindingInterpreter.unbox(o, callingSequence.returnBindings(), 115 (storage, type, value) -> { 116 MemoryAddress ptr = bufferBase.addOffset(layout.retOffset(storage)); 117 SharedUtils.writeOverSized(ptr, type, value); 118 }, null); 119 } 120 121 if (DEBUG) { 122 System.err.println("Buffer state after:"); 123 layout.dump(abi.arch, buffer, System.err); 124 } 125 } catch (Throwable t) { 126 throw new IllegalStateException(t); 127 } 128 } 129 130 public native long allocateUpcallStub(ABIDescriptor abi, BufferLayout layout); 131 132 private static native void registerNatives(); 133 static { 134 registerNatives(); 135 } 136 }