1 /* 2 * Copyright (c) 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.incubator.foreign.FunctionDescriptor; 26 import jdk.incubator.foreign.MemoryAddress; 27 import jdk.incubator.foreign.MemoryLayout; 28 import jdk.incubator.foreign.MemorySegment; 29 import sun.security.action.GetPropertyAction; 30 31 import java.lang.invoke.MethodType; 32 import java.util.ArrayDeque; 33 import java.util.ArrayList; 34 import java.util.Deque; 35 import java.util.List; 36 37 public class CallingSequenceBuilder { 38 private static final boolean VERIFY_BINDINGS = Boolean.parseBoolean( 39 GetPropertyAction.privilegedGetProperty("jdk.incubator.foreign.VERIFY_BINDINGS", "true")); 40 41 private final boolean forUpcall; 42 private final List<List<Binding>> inputBindings = new ArrayList<>(); 43 private List<Binding> outputBindings = List.of(); 44 45 private MethodType mt = MethodType.methodType(void.class); 46 private FunctionDescriptor desc = FunctionDescriptor.ofVoid(); 47 48 public CallingSequenceBuilder(boolean forUpcall) { 49 this.forUpcall = forUpcall; 50 } 51 52 public final CallingSequenceBuilder addArgumentBindings(Class<?> carrier, MemoryLayout layout, 53 List<Binding> bindings) { 54 verifyBindings(true, carrier, bindings); 55 inputBindings.add(bindings); 56 mt = mt.appendParameterTypes(carrier); 57 desc = desc.appendArgumentLayouts(layout); 58 return this; 59 } 60 61 public CallingSequenceBuilder setReturnBindings(Class<?> carrier, MemoryLayout layout, 62 List<Binding> bindings) { 63 verifyBindings(false, carrier, bindings); 64 this.outputBindings = bindings; 65 mt = mt.changeReturnType(carrier); 66 desc = desc.changeReturnLayout(layout); 67 return this; 68 } 69 70 public CallingSequence build() { 71 return new CallingSequence(mt, desc, inputBindings, outputBindings); 72 } 73 74 private void verifyBindings(boolean forArguments, Class<?> carrier, List<Binding> bindings) { 75 if (VERIFY_BINDINGS) { 76 if (forUpcall == forArguments) { 77 verifyBoxBindings(carrier, bindings); 78 } else { 79 verifyUnboxBindings(carrier, bindings); 80 } 81 } 82 } 83 84 private static void checkType(Class<?> actualType, Class<?> expectedType) { 85 if (expectedType != actualType) { 86 throw new IllegalArgumentException( 87 String.format("Invalid operand type: %s. %s expected", actualType, expectedType)); 88 } 89 } 90 91 private static void verifyUnboxBindings(Class<?> inType, List<Binding> bindings) { 92 Deque<Class<?>> stack = new ArrayDeque<>(); 93 stack.push(inType); 94 95 for (Binding b : bindings) { 96 switch (b.tag()) { 97 case MOVE -> { 98 Class<?> actualType = stack.pop(); 99 Class<?> expectedType = ((Binding.Move) b).type(); 100 checkType(actualType, expectedType); 101 } 102 case DEREFERENCE -> { 103 Class<?> actualType = stack.pop(); 104 checkType(actualType, MemorySegment.class); 105 Class<?> newType = ((Binding.Dereference) b).type(); 106 stack.push(newType); 107 } 108 case BASE_ADDRESS -> { 109 Class<?> actualType = stack.pop(); 110 checkType(actualType, MemorySegment.class); 111 stack.push(MemoryAddress.class); 112 } 113 case CONVERT_ADDRESS -> { 114 Class<?> actualType = stack.pop(); 115 checkType(actualType, MemoryAddress.class); 116 stack.push(long.class); 117 } 118 case ALLOC_BUFFER -> 119 throw new UnsupportedOperationException(); 120 case COPY_BUFFER -> { 121 Class<?> actualType = stack.pop(); 122 checkType(actualType, MemorySegment.class); 123 stack.push(MemorySegment.class); 124 } 125 case DUP -> 126 stack.push(stack.peekLast()); 127 default -> throw new IllegalArgumentException("Unknown binding: " + b); 128 } 129 } 130 131 if (!stack.isEmpty()) { 132 throw new IllegalArgumentException("Stack must be empty after recipe"); 133 } 134 } 135 136 private static void verifyBoxBindings(Class<?> outType, List<Binding> bindings) { 137 Deque<Class<?>> stack = new ArrayDeque<>(); 138 139 for (Binding b : bindings) { 140 switch (b.tag()) { 141 case MOVE -> { 142 Class<?> newType = ((Binding.Move) b).type(); 143 stack.push(newType); 144 } 145 case DEREFERENCE -> { 146 Class<?> storeType = stack.pop(); 147 checkType(storeType, ((Binding.Dereference) b).type()); 148 Class<?> segmentType = stack.pop(); 149 checkType(segmentType, MemorySegment.class); 150 } 151 case CONVERT_ADDRESS -> { 152 Class<?> actualType = stack.pop(); 153 checkType(actualType, long.class); 154 stack.push(MemoryAddress.class); 155 } 156 case BASE_ADDRESS -> { 157 Class<?> actualType = stack.pop(); 158 checkType(actualType, MemorySegment.class); 159 stack.push(MemoryAddress.class); 160 } 161 case ALLOC_BUFFER -> { 162 stack.push(MemorySegment.class); 163 } 164 case COPY_BUFFER -> { 165 Class<?> actualType = stack.pop(); 166 checkType(actualType, MemoryAddress.class); 167 stack.push(MemorySegment.class); 168 } 169 case DUP -> 170 stack.push(stack.peekLast()); 171 default -> throw new IllegalArgumentException("Unknown binding: " + b); 172 } 173 } 174 175 if (stack.size() != 1) { 176 throw new IllegalArgumentException("Stack must contain exactly 1 value"); 177 } 178 179 Class<?> actualReturnType = stack.pop(); 180 checkType(actualReturnType, outType); 181 } 182 }