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 }