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 import optkl.util.carriers.FuncOpCarrier;
32
33 import java.lang.invoke.MethodHandles;
34 import java.lang.reflect.Method;
35 import java.util.Objects;
36 import java.util.stream.Stream;
37
38 public class MethodCallDag extends Dag<MethodCallDag.Call> {
39 public abstract static class Call implements FuncOpCarrier {
40 private final MethodRef methodRef;
41 private final Method method;
42 private CoreOp.FuncOp funcOp;
43 Call(MethodRef methodRef, Method method, CoreOp.FuncOp funcOp){
44 this.methodRef = methodRef;
45 this.method = method;
46 this.funcOp = funcOp;
47 }
48
49 @Override
50 public int hashCode() {
51 return Objects.hash(methodRef,method); // We exclude the funcOp!
52 }
53
54 @Override
55 public boolean equals(Object o) {
56 return (this == o)
57 || ( o instanceof Call that
58 && Objects.equals(methodRef, that.methodRef) && Objects.equals(method, that.method) // we exclude the funcOp
59 );
60 }
61
62 @Override
63 public CoreOp.FuncOp funcOp(){
64 return this.funcOp;
65 }
66 @Override
67 public void funcOp(CoreOp.FuncOp funcOp){
68 this.funcOp = funcOp;
69 }
70 public Method method(){return method;}
71 public MethodRef methodRef(){
72 return this.methodRef;
73 }
74 }
75
76 public static class EntryMethodCall extends Call {
77 EntryMethodCall( Method method, CoreOp.FuncOp funcOp) {
78 super(null, method, funcOp); // we dont have a methodRef for the root
79 }
80 }
81 public static class OtherMethodCall extends Call {
82 OtherMethodCall(OpHelper.Invoke invoke) {
83 super(invoke.op().invokeReference(), invoke.resolveMethodOrThrow(),invoke.targetMethodModelOrNull()); // we dont have a methodRef for the root
84 }
85 }
86
87
88 public final EntryMethodCall entryPoint;
89 public final CoreOp.FuncOp inlined;
90
91 // recursive
92 void addEdge(Call from, OpHelper.Invoke invoke) {
93 var to = new OtherMethodCall(invoke);
94 add(from,to, _-> //only called if from->to is a new 'edge'
95 OpHelper.Invoke.stream(invoke.lookup(), to.funcOp()).filter((inv) -> inv.targetMethodModelOrNull() != null).forEach(i ->
96 addEdge(to, i) // recurses here
97 )
98 );
99 }
100
101 MethodCallDag(MethodHandles.Lookup lookup, Method method, CoreOp.FuncOp entry, CoreOp.FuncOp inlined) {
102 this.inlined = inlined;
103 this.entryPoint = new EntryMethodCall(method,entry);
104 OpHelper.Invoke.stream(lookup, entry)
105 .filter((inv)-> inv.targetMethodModelOrNull() != null)
106 .forEach(i ->
107 addEdge(entryPoint, i)
108 );
109 closeRanks();
110 }
111 }