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) {
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 }
|
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.MemoryLayout;
27 import sun.security.action.GetPropertyAction;
28
29 import java.lang.invoke.MethodType;
30 import java.util.ArrayDeque;
31 import java.util.ArrayList;
32 import java.util.Deque;
33 import java.util.List;
34
35 public class CallingSequenceBuilder {
36 private static final boolean VERIFY_BINDINGS = Boolean.parseBoolean(
37 GetPropertyAction.privilegedGetProperty("jdk.incubator.foreign.VERIFY_BINDINGS", "true"));
38
39 private final boolean forUpcall;
40 private final List<List<Binding>> inputBindings = new ArrayList<>();
41 private List<Binding> outputBindings = List.of();
42
43 private MethodType mt = MethodType.methodType(void.class);
44 private FunctionDescriptor desc = FunctionDescriptor.ofVoid();
45
46 public CallingSequenceBuilder(boolean forUpcall) {
62 this.outputBindings = bindings;
63 mt = mt.changeReturnType(carrier);
64 desc = desc.changeReturnLayout(layout);
65 return this;
66 }
67
68 public CallingSequence build() {
69 return new CallingSequence(mt, desc, inputBindings, outputBindings);
70 }
71
72 private void verifyBindings(boolean forArguments, Class<?> carrier, List<Binding> bindings) {
73 if (VERIFY_BINDINGS) {
74 if (forUpcall == forArguments) {
75 verifyBoxBindings(carrier, bindings);
76 } else {
77 verifyUnboxBindings(carrier, bindings);
78 }
79 }
80 }
81
82 private static void verifyUnboxBindings(Class<?> inType, List<Binding> bindings) {
83 Deque<Class<?>> stack = new ArrayDeque<>();
84 stack.push(inType);
85
86 for (Binding b : bindings) {
87 b.verifyUnbox(stack);
88 }
89
90 if (!stack.isEmpty()) {
91 throw new IllegalArgumentException("Stack must be empty after recipe");
92 }
93 }
94
95 private static void verifyBoxBindings(Class<?> expectedReturnType, List<Binding> bindings) {
96 Deque<Class<?>> stack = new ArrayDeque<>();
97
98 for (Binding b : bindings) {
99 b.verifyBox(stack);
100 }
101
102 if (stack.size() != 1) {
103 throw new IllegalArgumentException("Stack must contain exactly 1 value");
104 }
105
106 Class<?> actualReturnType = stack.pop();
107 SharedUtils.checkType(actualReturnType, expectedReturnType);
108 }
109 }
|