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 hat.callgraph;
26
27 import jdk.incubator.code.dialect.core.CoreOp;
28 import jdk.incubator.code.dialect.java.MethodRef;
29 import optkl.OpHelper;
30 import optkl.util.Dag;
31
32 import java.lang.invoke.MethodHandles;
33 import java.lang.reflect.Method;
34 import java.util.ArrayList;
35 import java.util.HashSet;
36 import java.util.List;
37 import java.util.Objects;
38
39 import static optkl.OpHelper.Invoke.invoke;
40 import static optkl.OpHelper.copyLocation;
41
42 public class MethodCallDag extends Dag<MethodCallDag.MethodInfo> {
43 static public class MethodInfo{
44 public CoreOp.FuncOp funcOp;
45
46 public final MethodRef methodRef;
47 public final Method method;
48 MethodInfo(CoreOp.FuncOp funcOp, MethodRef methodRef, Method method){
49 this.funcOp = funcOp;
50 this.methodRef = methodRef;
51 this.method = method;
52 }
53
54 @Override
55 public int hashCode() {
56 return Objects.hash(methodRef,method);
57 }
58 @Override
59 public boolean equals(Object o) {
60 if (this == o) return true;
61 return o instanceof MethodInfo that &&
62 Objects.equals(methodRef, that.methodRef) && Objects.equals(method, that.method);
63 }
64
65 static MethodInfo of(CoreOp.FuncOp funcOp, MethodRef methodRef, Method method) {
66 return new MethodInfo(funcOp, methodRef, method);
67 }
68 }
69
70 final MethodInfo entryPoint;
71 final CoreOp.FuncOp inlined;
72
73 MethodCallDag(MethodHandles.Lookup lookup, Method method, CoreOp.FuncOp funcOp, CoreOp.FuncOp inlined) {
74 super(lookup);
75 this.inlined = inlined;
76 this.entryPoint = MethodInfo.of(funcOp, null, method);// we dont have a methodRef for the root
77 nodeSet.add(this.entryPoint);
78 fromToNodes.put(this.entryPoint,new HashSet<>());
79 }
80
81 // recursive
82 void addEdge(MethodInfo methodInfo, OpHelper.Invoke invoke) {
83 computeIfAbsent(methodInfo,MethodInfo.of(invoke.targetMethodModelOrNull(), invoke.op().invokeReference(), invoke.resolveMethodOrThrow()), n->
84 OpHelper.Invoke.stream(invoke.lookup(), n.funcOp)
85 .filter(i -> i.targetMethodModelOrNull() != null)
86 .forEach(i -> addEdge(n, i))
87 );
88 }
89
90 static public MethodCallDag of(MethodHandles.Lookup lookup, Method method, CoreOp.FuncOp entry, CoreOp.FuncOp inlined) {
91 var dag = new MethodCallDag(lookup, method, entry, inlined);
92 OpHelper.Invoke.stream(lookup, entry)
93 .filter(invoke -> invoke.targetMethodModelOrNull() != null)
94 .forEach(i -> dag.addEdge(dag.entryPoint, i));
95 dag.closeRanks();
96 return dag;
97 }
98
99
100
101 public CoreOp.ModuleOp toModuleOp() {
102 List<CoreOp.FuncOp> moduleFuncOps = new ArrayList<>();
103 rankOrdered.forEach(methodInfo -> {
104 if (methodInfo.methodRef != null) {
105 CoreOp.FuncOp tf = methodInfo.funcOp.transform(methodInfo.methodRef.name(), (blockBuilder, op) -> {
106 if (invoke(lookup, op) instanceof OpHelper.Invoke invoke && invoke.targetMethodModelOrNull() instanceof CoreOp.FuncOp funcOp) {
107 var funcCall = copyLocation(funcOp,
108 CoreOp.funcCall(funcOp.funcName(), funcOp.invokableType(), blockBuilder.context().getValues(invoke.op().operands()))
109 );
110 blockBuilder.context().mapValue(op.result(), blockBuilder.op(funcCall));
111 } else {
112 blockBuilder.op(op);
113 }
114 return blockBuilder;
115 });
116 moduleFuncOps.add(tf);
117 }
118 }
119 );
120 return CoreOp.module(moduleFuncOps);
121 }
122
123 }