1 /*
  2  * Copyright (c) 2025, 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 oracle.code.samples;
 26 
 27 import jdk.incubator.code.Block;
 28 import jdk.incubator.code.Op;
 29 import jdk.incubator.code.Value;
 30 import jdk.incubator.code.bytecode.BytecodeGenerator;
 31 import jdk.incubator.code.dialect.core.CoreOp;
 32 import jdk.incubator.code.dialect.core.CoreType;
 33 import jdk.incubator.code.dialect.java.JavaOp;
 34 import jdk.incubator.code.dialect.java.JavaOp.InvokeOp.InvokeKind;
 35 import jdk.incubator.code.dialect.java.JavaType;
 36 import jdk.incubator.code.dialect.java.MethodRef;
 37 
 38 import java.lang.invoke.MethodHandle;
 39 import java.lang.invoke.MethodHandles;
 40 import java.util.ArrayList;
 41 import java.util.List;
 42 
 43 /**
 44  * Demonstrates how to dynamically build a new function using the code reflection API.
 45  * <p>
 46  * This example creates an <code>rsqrt</code> function, which computes the inverse of a square root.
 47  * The function takes one argument of type <code>double</code> and returns a <code>double</code>.
 48  * The implementation uses {@link Math#sqrt(double)} for the square root calculation.
 49  * </p>
 50  *
 51  * <p>
 52  * In this example, you will learn how to:
 53  * <ol>
 54  *   <li>Create a function dynamically</li>
 55  *   <li>Append new Op nodes in the builder</li>
 56  *   <li>Compose operations in the code tree</li>
 57  *   <li>Create nodes to call static methods</li>
 58  *   <li>Evaluate the composed method in the interpreter</li>
 59  * </ol>
 60  * </p>
 61  *
 62  * <p>
 63  * After building the code model for the function, it will be executed both in the code reflection interpreter and in the bytecode interpreter.
 64  * </p>
 65  *
 66  * <p>
 67  * <b>How to run:</b><br>
 68  * <code>
 69  * java --add-modules jdk.incubator.code -cp target/crsamples-1.0-SNAPSHOT.jar oracle.code.samples.DynamicFunctionBuild
 70  * </code>
 71  * </p>
 72  */
 73 public class DynamicFunctionBuild {
 74 
 75     static void main() {
 76 
 77         CoreOp.FuncOp myFunction = CoreOp.func("rsqrt",
 78                 // Define the signature of our new method
 79                 // The function will be called `rsqrt`:
 80                 // rsqrt(double):double
 81                 CoreType.functionType(JavaType.DOUBLE, JavaType.DOUBLE))
 82                 .body(builder -> {
 83 
 84                     // The function to build is as follows:
 85                     // double: function rsqrt(double input)
 86                     //      ret double: 1 / Math.sqrt(input)
 87                     //
 88 
 89                     // Obtain the first parameter
 90                     Block.Parameter inputParameter = builder.parameters().get(0);
 91 
 92                     // Create an op to represent the constant 1
 93                     CoreOp.ConstantOp constant1 = CoreOp.constant(JavaType.DOUBLE, 1.0);
 94                     // Add the Op into the builder
 95                     Op.Result constantResult = builder.op(constant1);
 96 
 97                     // Create a MethodRef to point to Math.sqrt
 98                     MethodRef sqrtMethodRef = MethodRef.method(Math.class, "sqrt", double.class, double.class);
 99 
100                     // Prepare the list of arguments for the Math.sqrt invoke
101                     List<Value> arguments = new ArrayList<>();
102                     arguments.add(inputParameter);
103 
104                     // Create an invoke Op
105                     JavaOp.InvokeOp invokeMathOp = JavaOp.invoke(InvokeKind.STATIC, false, JavaType.DOUBLE, sqrtMethodRef, arguments);
106 
107                     // Add the invoke op into the builder
108                     Op.Result invokeResult = builder.op(invokeMathOp);
109 
110                     // Create a division node and add it to the code builder
111                     JavaOp.BinaryOp divOp = JavaOp.div(constantResult, invokeResult);
112                     Op.Result divResult = builder.op(divOp);
113 
114                     // Finally, add a return and add it to the code builder
115                     CoreOp.ReturnOp retOp = CoreOp.return_(divResult);
116                     builder.op(retOp);
117                 });
118 
119         // Print the code model for the function we have just created
120         System.out.println(myFunction.toText());
121 
122         // Generate bytecode
123         MethodHandle generate = BytecodeGenerator.generate(MethodHandles.lookup(), myFunction);
124         try {
125             Object result = generate.invoke(100);
126             System.out.println("Result of bytecode executions: 1/sqrt(100) = " + result);
127         } catch (Throwable e) {
128             throw new RuntimeException(e);
129         }
130     }
131 }