Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/jdk/java/foreign/CallGeneratorHelper.java
41145 views
1
/*
2
* Copyright (c) 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.
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
25
import jdk.incubator.foreign.GroupLayout;
26
import jdk.incubator.foreign.MemoryAddress;
27
import jdk.incubator.foreign.MemoryLayout;
28
import jdk.incubator.foreign.MemorySegment;
29
import jdk.incubator.foreign.ResourceScope;
30
import jdk.incubator.foreign.SegmentAllocator;
31
import jdk.incubator.foreign.ValueLayout;
32
33
import java.lang.invoke.VarHandle;
34
import java.util.ArrayList;
35
import java.util.List;
36
import java.util.Stack;
37
import java.util.function.Consumer;
38
import java.util.stream.Collectors;
39
import java.util.stream.IntStream;
40
41
import org.testng.annotations.*;
42
43
import static jdk.incubator.foreign.CLinker.*;
44
import static org.testng.Assert.*;
45
46
public class CallGeneratorHelper extends NativeTestHelper {
47
48
static SegmentAllocator IMPLICIT_ALLOCATOR = (size, align) -> MemorySegment.allocateNative(size, align, ResourceScope.newImplicitScope());
49
50
static final int MAX_FIELDS = 3;
51
static final int MAX_PARAMS = 3;
52
static final int CHUNK_SIZE = 600;
53
54
public static void assertStructEquals(MemorySegment actual, MemorySegment expected, MemoryLayout layout) {
55
assertEquals(actual.byteSize(), expected.byteSize());
56
GroupLayout g = (GroupLayout) layout;
57
for (MemoryLayout field : g.memberLayouts()) {
58
if (field instanceof ValueLayout) {
59
VarHandle vh = g.varHandle(vhCarrier(field), MemoryLayout.PathElement.groupElement(field.name().orElseThrow()));
60
assertEquals(vh.get(actual), vh.get(expected));
61
}
62
}
63
}
64
65
private static Class<?> vhCarrier(MemoryLayout layout) {
66
if (layout instanceof ValueLayout) {
67
if (isIntegral(layout)) {
68
if (layout.bitSize() == 64) {
69
return long.class;
70
}
71
return int.class;
72
} else if (layout.bitSize() == 32) {
73
return float.class;
74
}
75
return double.class;
76
} else {
77
throw new IllegalStateException("Unexpected layout: " + layout);
78
}
79
}
80
81
enum Ret {
82
VOID,
83
NON_VOID
84
}
85
86
enum StructFieldType {
87
INT("int", C_INT),
88
FLOAT("float", C_FLOAT),
89
DOUBLE("double", C_DOUBLE),
90
POINTER("void*", C_POINTER);
91
92
final String typeStr;
93
final MemoryLayout layout;
94
95
StructFieldType(String typeStr, MemoryLayout layout) {
96
this.typeStr = typeStr;
97
this.layout = layout;
98
}
99
100
MemoryLayout layout() {
101
return layout;
102
}
103
104
@SuppressWarnings("unchecked")
105
static List<List<StructFieldType>>[] perms = new List[10];
106
107
static List<List<StructFieldType>> perms(int i) {
108
if (perms[i] == null) {
109
perms[i] = generateTest(i, values());
110
}
111
return perms[i];
112
}
113
}
114
115
enum ParamType {
116
INT("int", C_INT),
117
FLOAT("float", C_FLOAT),
118
DOUBLE("double", C_DOUBLE),
119
POINTER("void*", C_POINTER),
120
STRUCT("struct S", null);
121
122
private final String typeStr;
123
private final MemoryLayout layout;
124
125
ParamType(String typeStr, MemoryLayout layout) {
126
this.typeStr = typeStr;
127
this.layout = layout;
128
}
129
130
String type(List<StructFieldType> fields) {
131
return this == STRUCT ?
132
typeStr + "_" + sigCode(fields) :
133
typeStr;
134
}
135
136
MemoryLayout layout(List<StructFieldType> fields) {
137
if (this == STRUCT) {
138
long offset = 0L;
139
List<MemoryLayout> layouts = new ArrayList<>();
140
for (StructFieldType field : fields) {
141
MemoryLayout l = field.layout();
142
long padding = offset % l.bitSize();
143
if (padding != 0) {
144
layouts.add(MemoryLayout.paddingLayout(padding));
145
offset += padding;
146
}
147
layouts.add(l.withName("field" + offset));
148
offset += l.bitSize();
149
}
150
return MemoryLayout.structLayout(layouts.toArray(new MemoryLayout[0]));
151
} else {
152
return layout;
153
}
154
}
155
156
@SuppressWarnings("unchecked")
157
static List<List<ParamType>>[] perms = new List[10];
158
159
static List<List<ParamType>> perms(int i) {
160
if (perms[i] == null) {
161
perms[i] = generateTest(i, values());
162
}
163
return perms[i];
164
}
165
}
166
167
static <Z> List<List<Z>> generateTest(int i, Z[] elems) {
168
List<List<Z>> res = new ArrayList<>();
169
generateTest(i, new Stack<>(), elems, res);
170
return res;
171
}
172
173
static <Z> void generateTest(int i, Stack<Z> combo, Z[] elems, List<List<Z>> results) {
174
if (i == 0) {
175
results.add(new ArrayList<>(combo));
176
} else {
177
for (Z z : elems) {
178
combo.push(z);
179
generateTest(i - 1, combo, elems, results);
180
combo.pop();
181
}
182
}
183
}
184
185
@DataProvider(name = "functions")
186
public static Object[][] functions() {
187
int functions = 0;
188
List<Object[]> downcalls = new ArrayList<>();
189
for (Ret r : Ret.values()) {
190
for (int i = 0; i <= MAX_PARAMS; i++) {
191
if (r != Ret.VOID && i == 0) continue;
192
for (List<ParamType> ptypes : ParamType.perms(i)) {
193
String retCode = r == Ret.VOID ? "V" : ptypes.get(0).name().charAt(0) + "";
194
String sigCode = sigCode(ptypes);
195
if (ptypes.contains(ParamType.STRUCT)) {
196
for (int j = 1; j <= MAX_FIELDS; j++) {
197
for (List<StructFieldType> fields : StructFieldType.perms(j)) {
198
String structCode = sigCode(fields);
199
int count = functions;
200
int fCode = functions++ / CHUNK_SIZE;
201
String fName = String.format("f%d_%s_%s_%s", fCode, retCode, sigCode, structCode);
202
downcalls.add(new Object[] { count, fName, r, ptypes, fields });
203
}
204
}
205
} else {
206
String structCode = sigCode(List.<StructFieldType>of());
207
int count = functions;
208
int fCode = functions++ / CHUNK_SIZE;
209
String fName = String.format("f%d_%s_%s_%s", fCode, retCode, sigCode, structCode);
210
downcalls.add(new Object[] { count, fName, r, ptypes, List.of() });
211
}
212
}
213
}
214
}
215
return downcalls.toArray(new Object[0][]);
216
}
217
218
static <Z extends Enum<Z>> String sigCode(List<Z> elems) {
219
return elems.stream().map(p -> p.name().charAt(0) + "").collect(Collectors.joining());
220
}
221
222
static void generateStructDecl(List<StructFieldType> fields) {
223
String structCode = sigCode(fields);
224
List<String> fieldDecls = new ArrayList<>();
225
for (int i = 0 ; i < fields.size() ; i++) {
226
fieldDecls.add(String.format("%s p%d;", fields.get(i).typeStr, i));
227
}
228
String res = String.format("struct S_%s { %s };", structCode,
229
fieldDecls.stream().collect(Collectors.joining(" ")));
230
System.out.println(res);
231
}
232
233
/* this can be used to generate the test header/implementation */
234
public static void main(String[] args) {
235
boolean header = args.length > 0 && args[0].equals("header");
236
boolean upcall = args.length > 1 && args[1].equals("upcall");
237
if (upcall) {
238
generateUpcalls(header);
239
} else {
240
generateDowncalls(header);
241
}
242
}
243
244
static void generateDowncalls(boolean header) {
245
if (header) {
246
System.out.println(
247
"#ifdef _WIN64\n" +
248
"#define EXPORT __declspec(dllexport)\n" +
249
"#else\n" +
250
"#define EXPORT\n" +
251
"#endif\n"
252
);
253
254
for (int j = 1; j <= MAX_FIELDS; j++) {
255
for (List<StructFieldType> fields : StructFieldType.perms(j)) {
256
generateStructDecl(fields);
257
}
258
}
259
} else {
260
System.out.println(
261
"#include \"libh\"\n" +
262
"#ifdef __clang__\n" +
263
"#pragma clang optimize off\n" +
264
"#elif defined __GNUC__\n" +
265
"#pragma GCC optimize (\"O0\")\n" +
266
"#elif defined _MSC_BUILD\n" +
267
"#pragma optimize( \"\", off )\n" +
268
"#endif\n"
269
);
270
}
271
272
for (Object[] downcall : functions()) {
273
String fName = (String)downcall[0];
274
Ret r = (Ret)downcall[1];
275
@SuppressWarnings("unchecked")
276
List<ParamType> ptypes = (List<ParamType>)downcall[2];
277
@SuppressWarnings("unchecked")
278
List<StructFieldType> fields = (List<StructFieldType>)downcall[3];
279
generateDowncallFunction(fName, r, ptypes, fields, header);
280
}
281
}
282
283
static void generateDowncallFunction(String fName, Ret ret, List<ParamType> params, List<StructFieldType> fields, boolean declOnly) {
284
String retType = ret == Ret.VOID ? "void" : params.get(0).type(fields);
285
List<String> paramDecls = new ArrayList<>();
286
for (int i = 0 ; i < params.size() ; i++) {
287
paramDecls.add(String.format("%s p%d", params.get(i).type(fields), i));
288
}
289
String sig = paramDecls.isEmpty() ?
290
"void" :
291
paramDecls.stream().collect(Collectors.joining(", "));
292
String body = ret == Ret.VOID ? "{ }" : "{ return p0; }";
293
String res = String.format("EXPORT %s f%s(%s) %s", retType, fName,
294
sig, declOnly ? ";" : body);
295
System.out.println(res);
296
}
297
298
static void generateUpcalls(boolean header) {
299
if (header) {
300
System.out.println(
301
"#ifdef _WIN64\n" +
302
"#define EXPORT __declspec(dllexport)\n" +
303
"#else\n" +
304
"#define EXPORT\n" +
305
"#endif\n"
306
);
307
308
for (int j = 1; j <= MAX_FIELDS; j++) {
309
for (List<StructFieldType> fields : StructFieldType.perms(j)) {
310
generateStructDecl(fields);
311
}
312
}
313
} else {
314
System.out.println(
315
"#include \"libh\"\n" +
316
"#ifdef __clang__\n" +
317
"#pragma clang optimize off\n" +
318
"#elif defined __GNUC__\n" +
319
"#pragma GCC optimize (\"O0\")\n" +
320
"#elif defined _MSC_BUILD\n" +
321
"#pragma optimize( \"\", off )\n" +
322
"#endif\n"
323
);
324
}
325
326
for (Object[] downcall : functions()) {
327
String fName = (String)downcall[0];
328
Ret r = (Ret)downcall[1];
329
@SuppressWarnings("unchecked")
330
List<ParamType> ptypes = (List<ParamType>)downcall[2];
331
@SuppressWarnings("unchecked")
332
List<StructFieldType> fields = (List<StructFieldType>)downcall[3];
333
generateUpcallFunction(fName, r, ptypes, fields, header);
334
}
335
}
336
337
static void generateUpcallFunction(String fName, Ret ret, List<ParamType> params, List<StructFieldType> fields, boolean declOnly) {
338
String retType = ret == Ret.VOID ? "void" : params.get(0).type(fields);
339
List<String> paramDecls = new ArrayList<>();
340
for (int i = 0 ; i < params.size() ; i++) {
341
paramDecls.add(String.format("%s p%d", params.get(i).type(fields), i));
342
}
343
String paramNames = IntStream.range(0, params.size())
344
.mapToObj(i -> "p" + i)
345
.collect(Collectors.joining(","));
346
String sig = paramDecls.isEmpty() ?
347
"" :
348
paramDecls.stream().collect(Collectors.joining(", ")) + ", ";
349
String body = String.format(ret == Ret.VOID ? "{ cb(%s); }" : "{ return cb(%s); }", paramNames);
350
List<String> paramTypes = params.stream().map(p -> p.type(fields)).collect(Collectors.toList());
351
String cbSig = paramTypes.isEmpty() ?
352
"void" :
353
paramTypes.stream().collect(Collectors.joining(", "));
354
String cbParam = String.format("%s (*cb)(%s)",
355
retType, cbSig);
356
357
String res = String.format("EXPORT %s %s(%s %s) %s", retType, fName,
358
sig, cbParam, declOnly ? ";" : body);
359
System.out.println(res);
360
}
361
362
//helper methods
363
364
@SuppressWarnings("unchecked")
365
static Object makeArg(MemoryLayout layout, List<Consumer<Object>> checks, boolean check) throws ReflectiveOperationException {
366
if (layout instanceof GroupLayout) {
367
MemorySegment segment = MemorySegment.allocateNative(layout, ResourceScope.newImplicitScope());
368
initStruct(segment, (GroupLayout)layout, checks, check);
369
return segment;
370
} else if (isPointer(layout)) {
371
MemorySegment segment = MemorySegment.allocateNative(1, ResourceScope.newImplicitScope());
372
if (check) {
373
checks.add(o -> {
374
try {
375
assertEquals(o, segment.address());
376
} catch (Throwable ex) {
377
throw new IllegalStateException(ex);
378
}
379
});
380
}
381
return segment.address();
382
} else if (layout instanceof ValueLayout) {
383
if (isIntegral(layout)) {
384
if (check) {
385
checks.add(o -> assertEquals(o, 42));
386
}
387
return 42;
388
} else if (layout.bitSize() == 32) {
389
if (check) {
390
checks.add(o -> assertEquals(o, 12f));
391
}
392
return 12f;
393
} else {
394
if (check) {
395
checks.add(o -> assertEquals(o, 24d));
396
}
397
return 24d;
398
}
399
} else {
400
throw new IllegalStateException("Unexpected layout: " + layout);
401
}
402
}
403
404
static void initStruct(MemorySegment str, GroupLayout g, List<Consumer<Object>> checks, boolean check) throws ReflectiveOperationException {
405
for (MemoryLayout l : g.memberLayouts()) {
406
if (l.isPadding()) continue;
407
VarHandle accessor = g.varHandle(structFieldCarrier(l), MemoryLayout.PathElement.groupElement(l.name().get()));
408
List<Consumer<Object>> fieldsCheck = new ArrayList<>();
409
Object value = makeArg(l, fieldsCheck, check);
410
if (isPointer(l)) {
411
value = ((MemoryAddress)value).toRawLongValue();
412
}
413
//set value
414
accessor.set(str, value);
415
//add check
416
if (check) {
417
assertTrue(fieldsCheck.size() == 1);
418
checks.add(o -> {
419
MemorySegment actual = (MemorySegment)o;
420
try {
421
if (isPointer(l)) {
422
fieldsCheck.get(0).accept(MemoryAddress.ofLong((long)accessor.get(actual)));
423
} else {
424
fieldsCheck.get(0).accept(accessor.get(actual));
425
}
426
} catch (Throwable ex) {
427
throw new IllegalStateException(ex);
428
}
429
});
430
}
431
}
432
}
433
434
static Class<?> structFieldCarrier(MemoryLayout layout) {
435
if (isPointer(layout)) {
436
return long.class;
437
} else if (layout instanceof ValueLayout) {
438
if (isIntegral(layout)) {
439
return int.class;
440
} else if (layout.bitSize() == 32) {
441
return float.class;
442
} else {
443
return double.class;
444
}
445
} else {
446
throw new IllegalStateException("Unexpected layout: " + layout);
447
}
448
}
449
450
static Class<?> paramCarrier(MemoryLayout layout) {
451
if (layout instanceof GroupLayout) {
452
return MemorySegment.class;
453
} if (isPointer(layout)) {
454
return MemoryAddress.class;
455
} else if (layout instanceof ValueLayout) {
456
if (isIntegral(layout)) {
457
return int.class;
458
} else if (layout.bitSize() == 32) {
459
return float.class;
460
} else {
461
return double.class;
462
}
463
} else {
464
throw new IllegalStateException("Unexpected layout: " + layout);
465
}
466
}
467
}
468
469