Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/jdk/java/foreign/TestUpcall.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
/*
26
* @test
27
* @requires ((os.arch == "amd64" | os.arch == "x86_64") & sun.arch.data.model == "64") | os.arch == "aarch64"
28
* @modules jdk.incubator.foreign/jdk.internal.foreign
29
* @build NativeTestHelper CallGeneratorHelper TestUpcall
30
*
31
* @run testng/othervm/timeout=240
32
* --enable-native-access=ALL-UNNAMED
33
* TestUpcall
34
*/
35
36
import jdk.incubator.foreign.CLinker;
37
import jdk.incubator.foreign.FunctionDescriptor;
38
import jdk.incubator.foreign.SymbolLookup;
39
import jdk.incubator.foreign.MemoryAddress;
40
import jdk.incubator.foreign.MemoryLayout;
41
import jdk.incubator.foreign.MemorySegment;
42
43
import jdk.incubator.foreign.ResourceScope;
44
import jdk.incubator.foreign.SegmentAllocator;
45
import org.testng.annotations.BeforeClass;
46
import org.testng.annotations.Test;
47
48
import java.lang.invoke.MethodHandle;
49
import java.lang.invoke.MethodHandles;
50
import java.lang.invoke.MethodType;
51
import java.util.ArrayList;
52
import java.util.List;
53
import java.util.concurrent.atomic.AtomicReference;
54
import java.util.function.Consumer;
55
import java.util.stream.Collectors;
56
57
import static java.lang.invoke.MethodHandles.insertArguments;
58
import static jdk.incubator.foreign.CLinker.C_POINTER;
59
import static org.testng.Assert.assertEquals;
60
61
62
public class TestUpcall extends CallGeneratorHelper {
63
64
static {
65
System.loadLibrary("TestUpcall");
66
}
67
static CLinker abi = CLinker.getInstance();
68
69
static final SymbolLookup LOOKUP = SymbolLookup.loaderLookup();
70
71
static MethodHandle DUMMY;
72
static MethodHandle PASS_AND_SAVE;
73
74
static {
75
try {
76
DUMMY = MethodHandles.lookup().findStatic(TestUpcall.class, "dummy", MethodType.methodType(void.class));
77
PASS_AND_SAVE = MethodHandles.lookup().findStatic(TestUpcall.class, "passAndSave",
78
MethodType.methodType(Object.class, Object[].class, AtomicReference.class));
79
} catch (Throwable ex) {
80
throw new IllegalStateException(ex);
81
}
82
}
83
84
static MemoryAddress dummyStub;
85
86
@BeforeClass
87
void setup() {
88
dummyStub = abi.upcallStub(DUMMY, FunctionDescriptor.ofVoid(), ResourceScope.newImplicitScope());
89
}
90
91
@Test(dataProvider="functions", dataProviderClass=CallGeneratorHelper.class)
92
public void testUpcalls(int count, String fName, Ret ret, List<ParamType> paramTypes, List<StructFieldType> fields) throws Throwable {
93
List<Consumer<Object>> returnChecks = new ArrayList<>();
94
List<Consumer<Object[]>> argChecks = new ArrayList<>();
95
MemoryAddress addr = LOOKUP.lookup(fName).get();
96
MethodType mtype = methodType(ret, paramTypes, fields);
97
try (NativeScope scope = new NativeScope()) {
98
MethodHandle mh = abi.downcallHandle(addr, scope, mtype, function(ret, paramTypes, fields));
99
Object[] args = makeArgs(scope.scope(), ret, paramTypes, fields, returnChecks, argChecks);
100
Object[] callArgs = args;
101
Object res = mh.invokeWithArguments(callArgs);
102
argChecks.forEach(c -> c.accept(args));
103
if (ret == Ret.NON_VOID) {
104
returnChecks.forEach(c -> c.accept(res));
105
}
106
}
107
}
108
109
@Test(dataProvider="functions", dataProviderClass=CallGeneratorHelper.class)
110
public void testUpcallsNoScope(int count, String fName, Ret ret, List<ParamType> paramTypes, List<StructFieldType> fields) throws Throwable {
111
List<Consumer<Object>> returnChecks = new ArrayList<>();
112
List<Consumer<Object[]>> argChecks = new ArrayList<>();
113
MemoryAddress addr = LOOKUP.lookup(fName).get();
114
MethodType mtype = methodType(ret, paramTypes, fields);
115
MethodHandle mh = abi.downcallHandle(addr, IMPLICIT_ALLOCATOR, mtype, function(ret, paramTypes, fields));
116
Object[] args = makeArgs(ResourceScope.newImplicitScope(), ret, paramTypes, fields, returnChecks, argChecks);
117
Object[] callArgs = args;
118
if (count % 100 == 0) {
119
System.gc();
120
}
121
Object res = mh.invokeWithArguments(callArgs);
122
argChecks.forEach(c -> c.accept(args));
123
if (ret == Ret.NON_VOID) {
124
returnChecks.forEach(c -> c.accept(res));
125
}
126
}
127
128
static MethodType methodType(Ret ret, List<ParamType> params, List<StructFieldType> fields) {
129
MethodType mt = ret == Ret.VOID ?
130
MethodType.methodType(void.class) : MethodType.methodType(paramCarrier(params.get(0).layout(fields)));
131
for (ParamType p : params) {
132
mt = mt.appendParameterTypes(paramCarrier(p.layout(fields)));
133
}
134
mt = mt.appendParameterTypes(MemoryAddress.class); //the callback
135
return mt;
136
}
137
138
static FunctionDescriptor function(Ret ret, List<ParamType> params, List<StructFieldType> fields) {
139
List<MemoryLayout> paramLayouts = params.stream().map(p -> p.layout(fields)).collect(Collectors.toList());
140
paramLayouts.add(C_POINTER); // the callback
141
MemoryLayout[] layouts = paramLayouts.toArray(new MemoryLayout[0]);
142
return ret == Ret.VOID ?
143
FunctionDescriptor.ofVoid(layouts) :
144
FunctionDescriptor.of(layouts[0], layouts);
145
}
146
147
static Object[] makeArgs(ResourceScope scope, Ret ret, List<ParamType> params, List<StructFieldType> fields, List<Consumer<Object>> checks, List<Consumer<Object[]>> argChecks) throws ReflectiveOperationException {
148
Object[] args = new Object[params.size() + 1];
149
for (int i = 0 ; i < params.size() ; i++) {
150
args[i] = makeArg(params.get(i).layout(fields), checks, i == 0);
151
}
152
args[params.size()] = makeCallback(scope, ret, params, fields, checks, argChecks);
153
return args;
154
}
155
156
@SuppressWarnings("unchecked")
157
static MemoryAddress makeCallback(ResourceScope scope, Ret ret, List<ParamType> params, List<StructFieldType> fields, List<Consumer<Object>> checks, List<Consumer<Object[]>> argChecks) {
158
if (params.isEmpty()) {
159
return dummyStub.address();
160
}
161
162
AtomicReference<Object[]> box = new AtomicReference<>();
163
MethodHandle mh = insertArguments(PASS_AND_SAVE, 1, box);
164
mh = mh.asCollector(Object[].class, params.size());
165
166
for (int i = 0; i < params.size(); i++) {
167
ParamType pt = params.get(i);
168
MemoryLayout layout = pt.layout(fields);
169
Class<?> carrier = paramCarrier(layout);
170
mh = mh.asType(mh.type().changeParameterType(i, carrier));
171
172
final int finalI = i;
173
if (carrier == MemorySegment.class) {
174
argChecks.add(o -> assertStructEquals((MemorySegment) box.get()[finalI], (MemorySegment) o[finalI], layout));
175
} else {
176
argChecks.add(o -> assertEquals(box.get()[finalI], o[finalI]));
177
}
178
}
179
180
ParamType firstParam = params.get(0);
181
MemoryLayout firstlayout = firstParam.layout(fields);
182
Class<?> firstCarrier = paramCarrier(firstlayout);
183
184
if (firstCarrier == MemorySegment.class) {
185
checks.add(o -> assertStructEquals((MemorySegment) box.get()[0], (MemorySegment) o, firstlayout));
186
} else {
187
checks.add(o -> assertEquals(o, box.get()[0]));
188
}
189
190
mh = mh.asType(mh.type().changeReturnType(ret == Ret.VOID ? void.class : firstCarrier));
191
192
MemoryLayout[] paramLayouts = params.stream().map(p -> p.layout(fields)).toArray(MemoryLayout[]::new);
193
FunctionDescriptor func = ret != Ret.VOID
194
? FunctionDescriptor.of(firstlayout, paramLayouts)
195
: FunctionDescriptor.ofVoid(paramLayouts);
196
return abi.upcallStub(mh, func, scope);
197
}
198
199
static Object passAndSave(Object[] o, AtomicReference<Object[]> ref) {
200
for (int i = 0; i < o.length; i++) {
201
if (o[i] instanceof MemorySegment) {
202
MemorySegment ms = (MemorySegment) o[i];
203
MemorySegment copy = MemorySegment.allocateNative(ms.byteSize(), ResourceScope.newImplicitScope());
204
copy.copyFrom(ms);
205
o[i] = copy;
206
}
207
}
208
ref.set(o);
209
return o[0];
210
}
211
212
static void dummy() {
213
//do nothing
214
}
215
}
216
217