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 }