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