1 /*
2 * Copyright (c) 2024, 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 experiments;
26
27
28 import hat.ifacemapper.Schema;
29 import hat.buffer.Buffer;
30 import hat.ifacemapper.MappableIface;
31
32 import java.lang.constant.ClassDesc;
33 import java.lang.foreign.*;
34 import java.lang.invoke.MethodHandles;
35 import java.lang.reflect.Field;
36 import java.lang.reflect.Method;
37
38 import hat.optools.OpTk;
39 import jdk.incubator.code.*;
40 import jdk.incubator.code.analysis.SSA;
41 import jdk.incubator.code.extern.ExternalizedTypeElement;
42 import jdk.incubator.code.extern.OpFactory;
43 import jdk.incubator.code.dialect.core.CoreOp;
44 import jdk.incubator.code.CodeReflection;
45 import jdk.incubator.code.dialect.core.CoreType;
46 import jdk.incubator.code.dialect.core.FunctionType;
47 import jdk.incubator.code.dialect.java.JavaOp;
48 import jdk.incubator.code.dialect.java.JavaType;
49 import jdk.incubator.code.dialect.java.PrimitiveType;
50
51 import java.util.*;
52 import java.util.stream.Stream;
53
54 public class LayoutExample {
55
56 /*
57 struct {
58 StructTwo struct;
59 int i;
60 }
61 */
62
63 public interface Outer extends Buffer {
64 interface Inner extends Struct {
65 int i();
66
67 void i(int v);
68
69 float f();
70
71 void f(float v);
72
73 // Schema schema = Schema.of(Inner.class, b->b.primitive("i").primitive("f"));
74 }
75
76 Inner right();
77 Inner left();
78 int i();
79 void i(int v);
80
81
82 Schema schema = Schema.of(Outer.class, b->b
83 .struct("left", left->left
84 .field("i")
85 .field("f")
86 )
87 // .struct("right", Inner.schema)
88 .field("i")
89 );
90 }
91
92
93 @CodeReflection
94 static float m(Outer s1) {
95 // StructOne* s1
96 // s1 -> i
97 int i = s1.i();
98 // s1 -> *s2
99 Outer.Inner s2 = s1.left();
100 // s2 -> i
101 i += s2.i();
102 // s2 -> f
103 float f = s2.f();
104 return i + f;
105 }
106
107
108 public static void main(String[] args) {
109 var lookup = MethodHandles.lookup();
110 Optional<Method> om = Stream.of(LayoutExample.class.getDeclaredMethods())
111 .filter(m -> m.getName().equals("m"))
112 .findFirst();
113
114 Method m = om.orElseThrow();
115 CoreOp.FuncOp f= Op.ofMethod(m).orElseThrow();
116 var here = OpTk.CallSite.of(LayoutExample.class, "main");
117 f = OpTk.SSATransform(here, f);
118 System.out.println(f.toText());
119 FunctionType functionType = transformStructClassToPtr(lookup, f);
120 System.out.println(f.toText());
121 CoreOp.FuncOp pm = transformInvokesToPtrs(lookup, f, functionType);
122 System.out.println(pm.toText());
123 }
124 static FunctionType transformStructClassToPtr(MethodHandles.Lookup l,
125 CoreOp.FuncOp f) {
126 List<TypeElement> pTypes = new ArrayList<>();
127 for (Block.Parameter p : f.parameters()) {
128 pTypes.add(transformStructClassToPtr(l, p.type()));
129 }
130 return CoreType.functionType(
131 transformStructClassToPtr(l, f.invokableType().returnType()), pTypes);
132 }
133
134 static CoreOp.FuncOp transformInvokesToPtrs(MethodHandles.Lookup l,
135 CoreOp.FuncOp f, FunctionType functionType) {
136
137 var builder= CoreOp.func(f.funcName(), functionType);
138
139 var funcOp = builder.body(funcBlock -> {
140 funcBlock.body(f.body(), funcBlock.parameters(), (b, op) -> {
141 if (op instanceof JavaOp.InvokeOp invokeOp
142 && invokeOp.hasReceiver()
143 && invokeOp.operands().getFirst() instanceof Value receiver) {
144 if (bufferOrBufferChildClass(l, receiver.type()) != null) {
145 Value ptr = b.context().getValue(receiver);
146 PtrToMember ptrToMemberOp = new PtrToMember(ptr, invokeOp.invokeDescriptor().name());
147 Op.Result memberPtr = b.op(ptrToMemberOp);
148
149 if (invokeOp.operands().size() == 1) {
150 // Pointer access and (possibly) value load
151 if (ptrToMemberOp.resultType().layout() instanceof ValueLayout) {
152 Op.Result v = b.op(new PtrLoadValue(memberPtr));
153 b.context().mapValue(invokeOp.result(), v);
154 } else {
155 b.context().mapValue(invokeOp.result(), memberPtr);
156 }
157 } else {
158 // @@@
159 // Value store
160 throw new UnsupportedOperationException();
161 }
162 } else {
163 b.op(op);
164 }
165 } else {
166 b.op(op);
167 }
168 return b;
169 });
170 });
171 return funcOp;
172 }
173
174
175
176 static boolean isBufferOrBufferChild(Class<?> maybeIface) {
177 return maybeIface.isInterface() && (
178 MappableIface.class.isAssignableFrom(maybeIface)
179 );
180
181 }
182 static Schema bufferOrBufferChildSchema(MethodHandles.Lookup l, Class<?> maybeBufferOrBufferChild) {
183 if (isBufferOrBufferChild(maybeBufferOrBufferChild)) {
184 throw new IllegalArgumentException();
185 }
186 Field schemaField;
187 try {
188 schemaField = maybeBufferOrBufferChild.getField("schema");
189 return (Schema)schemaField.get(null);
190 } catch (NoSuchFieldException | IllegalAccessException e) {
191 throw new RuntimeException(e);
192 }
193 }
194 static Class<?> bufferOrBufferChildClass(MethodHandles.Lookup l, TypeElement t) {
195 try {
196 if (!(t instanceof JavaType jt) || !(jt.resolve(l) instanceof Class<?> c)) {
197 return null;
198 }
199 return isBufferOrBufferChild(c) ? c : null;
200 } catch (ReflectiveOperationException e) {
201 throw new RuntimeException(e);
202 }
203 }
204 static TypeElement transformStructClassToPtr(MethodHandles.Lookup l, TypeElement type) {
205 if (bufferOrBufferChildClass(l, type) instanceof Class<?> sc) {
206 return new PtrType(bufferOrBufferChildSchema(l, sc));
207 } else {
208 return type;
209 }
210 }
211
212 public static final class PtrType implements TypeElement {
213 static final String NAME = "ptr";
214 MemoryLayout layout;
215 Schema schema;
216 final JavaType returnType;
217
218 public PtrType(MemoryLayout layout) {
219 this.layout = layout;
220 this.returnType = switch (layout) {
221 case StructLayout _ -> JavaType.type(ClassDesc.of(layout.name().orElseThrow()));
222 case AddressLayout _ -> throw new UnsupportedOperationException("Unsupported member layout: " + layout);
223 case ValueLayout valueLayout -> JavaType.type(valueLayout.carrier());
224 default -> throw new UnsupportedOperationException("Unsupported member layout: " + layout);
225 };
226 }
227 public PtrType(Schema schema) {
228 this.schema = schema;
229 this.layout= null;//schema.layout();
230 this.returnType = switch (layout) {
231 case StructLayout _ -> JavaType.type(ClassDesc.of(layout.name().orElseThrow()));
232 case AddressLayout _ -> throw new UnsupportedOperationException("Unsupported member layout: " + layout);
233 case ValueLayout valueLayout -> JavaType.type(valueLayout.carrier());
234 default -> throw new UnsupportedOperationException("Unsupported member layout: " + layout);
235 };
236 }
237
238 public JavaType returnType() {
239 return returnType;
240 }
241
242 public MemoryLayout layout() {
243 return layout;
244 }
245 public Schema schema() {
246 return schema;
247 }
248
249 @Override
250 public boolean equals(Object o) {
251 if (this == o) return true;
252 if (o == null || getClass() != o.getClass()) return false;
253 PtrType ptrType = (PtrType) o;
254 return Objects.equals(layout, ptrType.layout);
255 }
256
257 @Override
258 public int hashCode() {
259 return Objects.hash(layout);
260 }
261
262 @Override
263 public ExternalizedTypeElement externalize() {
264 return new ExternalizedTypeElement(NAME, List.of(returnType.externalize()));
265 }
266
267 @Override
268 public String toString() {
269 return externalize().toString();
270 }
271 }
272
273 public static final class PtrToMember extends Op {
274 public static final String NAME = "ptr.to.member";
275 public static final String ATTRIBUTE_OFFSET = "offset";
276 public static final String ATTRIBUTE_NAME = "name";
277
278 final String simpleMemberName;
279 final long memberOffset;
280 final PtrType resultType;
281
282 PtrToMember(PtrToMember that, CopyContext cc) {
283 super(that, cc);
284 this.simpleMemberName = that.simpleMemberName;
285 this.memberOffset = that.memberOffset;
286 this.resultType = that.resultType;
287 }
288
289 @Override
290 public PtrToMember transform(CopyContext cc, OpTransformer ot) {
291 return new PtrToMember(this, cc);
292 }
293
294 public PtrToMember(Value ptr, String simpleMemberName) {
295 super(List.of(ptr));
296 this.simpleMemberName = simpleMemberName;
297
298 if (!(ptr.type() instanceof PtrType ptrType)) {
299 throw new IllegalArgumentException("Pointer value is not of pointer type: " + ptr.type());
300 }
301 // @@@ Support group layout
302 if (!(ptrType.layout() instanceof StructLayout structLayout)) {
303 throw new IllegalArgumentException("Pointer type layout is not a struct layout: " + ptrType.layout());
304 }
305
306 // Find the actual member name from the simple member name
307 String memberName = findMemberName(structLayout, simpleMemberName);
308 MemoryLayout.PathElement p = MemoryLayout.PathElement.groupElement(memberName);
309 this.memberOffset = structLayout.byteOffset(p);
310 MemoryLayout memberLayout = structLayout.select(p);
311 // Remove any simple member name from the layout
312 MemoryLayout ptrLayout = memberLayout instanceof StructLayout
313 ? memberLayout.withName(className(memberName))
314 : memberLayout.withoutName();
315 this.resultType = new PtrType(ptrLayout);
316 }
317
318 // @@@ Change to return member index
319 static String findMemberName(StructLayout sl, String simpleMemberName) {
320 for (MemoryLayout layout : sl.memberLayouts()) {
321 String memberName = layout.name().orElseThrow();
322 if (simpleMemberName(memberName).equals(simpleMemberName)) {
323 return memberName;
324 }
325 }
326 throw new NoSuchElementException("No member found: " + simpleMemberName + " " + sl);
327 }
328
329 static String simpleMemberName(String memberName) {
330 int i = memberName.indexOf("::");
331 return i != -1
332 ? memberName.substring(i + 2)
333 : memberName;
334 }
335
336 static String className(String memberName) {
337 int i = memberName.indexOf("::");
338 return i != -1
339 ? memberName.substring(0, i)
340 : null;
341 }
342
343 @Override
344 public PtrType resultType() {
345 return resultType;
346 }
347
348 @Override
349 public String externalizeOpName() {
350 return NAME;
351 }
352
353 @Override
354 public Map<String, Object> externalize() {
355 return Map.of(
356 "", simpleMemberName,
357 ATTRIBUTE_OFFSET, memberOffset);
358 }
359
360 public String simpleMemberName() {
361 return simpleMemberName;
362 }
363
364 public long memberOffset() {
365 return memberOffset;
366 }
367
368 public Value ptrValue() {
369 return operands().get(0);
370 }
371 }
372
373
374 public static final class PtrAddOffset extends Op {
375 public static final String NAME = "ptr.add.offset";
376
377 PtrAddOffset(PtrAddOffset that, CopyContext cc) {
378 super(that, cc);
379 }
380
381 @Override
382 public PtrAddOffset transform(CopyContext cc, OpTransformer ot) {
383 return new PtrAddOffset(this, cc);
384 }
385
386 public PtrAddOffset(Value ptr, Value offset) {
387 super(List.of(ptr, offset));
388
389 if (!(ptr.type() instanceof PtrType)) {
390 throw new IllegalArgumentException("Pointer value is not of pointer type: " + ptr.type());
391 }
392 if (!(offset.type() instanceof PrimitiveType pt && pt.equals(JavaType.LONG))) {
393 throw new IllegalArgumentException("Offset value is not of primitve long type: " + offset.type());
394 }
395 }
396
397 @Override
398 public TypeElement resultType() {
399 return ptrValue().type();
400 }
401
402 @Override
403 public String externalizeOpName() {
404 return NAME;
405 }
406
407 public Value ptrValue() {
408 return operands().get(0);
409 }
410
411 public Value offsetValue() {
412 return operands().get(1);
413 }
414 }
415
416 public static final class PtrLoadValue extends Op {
417 public static final String NAME = "ptr.load.value";
418
419 final JavaType resultType;
420
421 PtrLoadValue(PtrLoadValue that, CopyContext cc) {
422 super(that, cc);
423 this.resultType = that.resultType;
424 }
425
426 @Override
427 public PtrLoadValue transform(CopyContext cc, OpTransformer ot) {
428 return new PtrLoadValue(this, cc);
429 }
430
431 public PtrLoadValue(Value ptr) {
432 super(List.of(ptr));
433
434 if (!(ptr.type() instanceof PtrType ptrType)) {
435 throw new IllegalArgumentException("Pointer value is not of pointer type: " + ptr.type());
436 }
437 if (!(ptrType.layout() instanceof ValueLayout)) {
438 throw new IllegalArgumentException("Pointer type layout is not a value layout: " + ptrType.layout());
439 }
440 this.resultType = ptrType.returnType();
441 }
442
443 @Override
444 public TypeElement resultType() {
445 return resultType;
446 }
447
448 @Override
449 public String externalizeOpName() {
450 return NAME;
451 }
452
453 public Value ptrValue() {
454 return operands().get(0);
455 }
456 }
457
458 public static final class PtrStoreValue extends Op {
459 public static final String NAME = "ptr.store.value";
460
461 PtrStoreValue(PtrStoreValue that, CopyContext cc) {
462 super(that, cc);
463 }
464
465 @Override
466 public PtrStoreValue transform(CopyContext cc, OpTransformer ot) {
467 return new PtrStoreValue(this, cc);
468 }
469
470 public PtrStoreValue(Value ptr, Value v) {
471 super(List.of(ptr));
472
473 if (!(ptr.type() instanceof PtrType ptrType)) {
474 throw new IllegalArgumentException("Pointer value is not of pointer type: " + ptr.type());
475 }
476 if (!(ptrType.layout() instanceof ValueLayout)) {
477 throw new IllegalArgumentException("Pointer type layout is not a value layout: " + ptrType.layout());
478 }
479 if (!(ptrType.returnType().equals(v.type()))) {
480 throw new IllegalArgumentException("Pointer reference type is not same as value to store type: "
481 + ptrType.returnType() + " " + v.type());
482 }
483 }
484
485 @Override
486 public TypeElement resultType() {
487 return JavaType.VOID;
488 }
489
490 @Override
491 public String externalizeOpName() {
492 return NAME;
493 }
494
495 public Value ptrValue() {
496 return operands().get(0);
497 }
498 }
499 }
500