1 /* 2 * Copyright (c) 2016, 2020, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 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 package jdk.internal.foreign.abi.x64.sysv; 26 27 import jdk.incubator.foreign.CSupport; 28 import jdk.incubator.foreign.ForeignLinker; 29 import jdk.incubator.foreign.FunctionDescriptor; 30 import jdk.incubator.foreign.MemoryAddress; 31 import jdk.incubator.foreign.MemoryLayout; 32 import jdk.incubator.foreign.MemorySegment; 33 import jdk.internal.foreign.abi.UpcallStubs; 34 35 import java.lang.invoke.MethodHandle; 36 import java.lang.invoke.MethodHandles; 37 import java.lang.invoke.MethodType; 38 import java.util.Optional; 39 import java.util.function.Consumer; 40 41 import static jdk.incubator.foreign.CSupport.*; 42 43 /** 44 * ABI implementation based on System V ABI AMD64 supplement v.0.99.6 45 */ 46 public class SysVx64Linker implements ForeignLinker { 47 public static final int MAX_INTEGER_ARGUMENT_REGISTERS = 6; 48 public static final int MAX_INTEGER_RETURN_REGISTERS = 2; 49 public static final int MAX_VECTOR_ARGUMENT_REGISTERS = 8; 50 public static final int MAX_VECTOR_RETURN_REGISTERS = 2; 51 public static final int MAX_X87_RETURN_REGISTERS = 2; 52 53 private static SysVx64Linker instance; 54 55 static final long ADDRESS_SIZE = 64; // bits 56 57 private static final MethodHandle MH_unboxVaList; 58 private static final MethodHandle MH_boxVaList; 59 60 static { 61 try { 62 MethodHandles.Lookup lookup = MethodHandles.lookup(); 63 MH_unboxVaList = lookup.findStatic(SysVx64Linker.class, "unboxVaList", 64 MethodType.methodType(MemoryAddress.class, CSupport.VaList.class)); 65 MH_boxVaList = lookup.findStatic(SysVx64Linker.class, "boxVaList", 66 MethodType.methodType(VaList.class, MemoryAddress.class)); 67 } catch (ReflectiveOperationException e) { 68 throw new ExceptionInInitializerError(e); 69 } 70 } 71 72 public static SysVx64Linker getInstance() { 73 if (instance == null) { 74 instance = new SysVx64Linker(); 75 } 76 return instance; 77 } 78 79 public static VaList newVaList(Consumer<VaList.Builder> actions) { 80 SysVVaList.Builder builder = SysVVaList.builder(); 81 actions.accept(builder); 82 return builder.build(); 83 } 84 85 private static MethodType convertVaListCarriers(MethodType mt) { 86 Class<?>[] params = new Class<?>[mt.parameterCount()]; 87 for (int i = 0; i < params.length; i++) { 88 Class<?> pType = mt.parameterType(i); 89 params[i] = ((pType == CSupport.VaList.class) ? SysVVaList.CARRIER : pType); 90 } 91 return MethodType.methodType(mt.returnType(), params); 92 } 93 94 private static MethodHandle unxboxVaLists(MethodType type, MethodHandle handle) { 95 for (int i = 0; i < type.parameterCount(); i++) { 96 if (type.parameterType(i) == VaList.class) { 97 handle = MethodHandles.filterArguments(handle, i, MH_unboxVaList); 98 } 99 } 100 return handle; 101 } 102 103 @Override 104 public MethodHandle downcallHandle(MemoryAddress symbol, MethodType type, FunctionDescriptor function) { 105 MethodType llMt = convertVaListCarriers(type); 106 MethodHandle handle = CallArranger.arrangeDowncall(symbol, llMt, function); 107 handle = unxboxVaLists(type, handle); 108 return handle; 109 } 110 111 private static MethodHandle boxVaLists(MethodHandle handle) { 112 MethodType type = handle.type(); 113 for (int i = 0; i < type.parameterCount(); i++) { 114 if (type.parameterType(i) == VaList.class) { 115 handle = MethodHandles.filterArguments(handle, i, MH_boxVaList); 116 } 117 } 118 return handle; 119 } 120 121 @Override 122 public MemorySegment upcallStub(MethodHandle target, FunctionDescriptor function) { 123 target = boxVaLists(target); 124 return UpcallStubs.upcallAddress(CallArranger.arrangeUpcall(target, target.type(), function)); 125 } 126 127 @Override 128 public String name() { 129 return SysV.NAME; 130 } 131 132 static Optional<ArgumentClassImpl> argumentClassFor(MemoryLayout layout) { 133 @SuppressWarnings({"unchecked", "rawtypes"}) 134 Optional<SysV.ArgumentClass> argClassOpt = 135 (Optional<SysV.ArgumentClass>)(Optional)layout.attribute(SysV.CLASS_ATTRIBUTE_NAME); 136 return argClassOpt.map(argClass -> switch (argClass) { 137 case INTEGER -> ArgumentClassImpl.INTEGER; 138 case SSE -> ArgumentClassImpl.SSE; 139 case X87 -> ArgumentClassImpl.X87; 140 case COMPLEX_87 -> ArgumentClassImpl.COMPLEX_X87; 141 case POINTER -> ArgumentClassImpl.POINTER; 142 default -> null; 143 }); 144 } 145 146 private static MemoryAddress unboxVaList(CSupport.VaList list) { 147 return ((SysVVaList) list).getSegment().baseAddress(); 148 } 149 150 private static CSupport.VaList boxVaList(MemoryAddress ma) { 151 return SysVVaList.ofAddress(ma); 152 } 153 154 public static VaList newVaListOfAddress(MemoryAddress ma) { 155 return SysVVaList.ofAddress(ma); 156 } 157 }