Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 123 additions & 0 deletions HelloCodeReflection.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/*
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Future Copyright Year

Copyright year 2025 is in the future. This creates a legally incorrect copyright statement that could affect licensing validity and create confusion about code origin date.

Suggested change
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
Standards
  • Business-Rule-Validation
  • Logic-Verification-Accuracy

* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package oracle.code.samples;

import jdk.incubator.code.Block;
import jdk.incubator.code.CodeElement;
import jdk.incubator.code.CodeReflection;
import jdk.incubator.code.Op;
import jdk.incubator.code.analysis.SSA;
import jdk.incubator.code.dialect.core.CoreOp;
import jdk.incubator.code.interpreter.Interpreter;

import java.lang.invoke.MethodHandles;
import java.lang.reflect.Method;
import java.util.Optional;
import java.util.stream.Stream;

/**
* Simple example of how to use the code reflection API, showing how to
* build a code model, lower it to an SSA representation and run it
* in an interpreter.
*
* <p>
* Babylon repository: {@see <a href="https://github.com/openjdk/babylon/tree/code-reflection">link</a>}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix JavaDoc syntax error

The JavaDoc link syntax is incorrect. Use @see instead of {@see.

- *     Babylon repository: {@see <a href="https://github.com/openjdk/babylon/tree/code-reflection">link</a>}
+ *     Babylon repository: @see <a href="https://github.com/openjdk/babylon/tree/code-reflection">link</a>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
* Babylon repository: {@see <a href="https://github.com/openjdk/babylon/tree/code-reflection">link</a>}
* Babylon repository: @see <a href="https://github.com/openjdk/babylon/tree/code-reflection">link</a>
🤖 Prompt for AI Agents
In HelloCodeReflection.java at line 46, the JavaDoc link uses incorrect syntax
with {@see. Replace {@see with @see to correct the JavaDoc link syntax and
ensure proper rendering of the reference.

* </p>
*
* <p>
* How to run?
* <code>
* java --enable-preview -cp target/crsamples-1.0-SNAPSHOT.jar oracle.code.samples.HelloCodeReflection
* </code>
* </p>
*/
public class HelloCodeReflection {

private int value;

private HelloCodeReflection(int value) {
this.value = value;
}

// instance method with no accessors to any field in the function body
@CodeReflection
private double myFunction(int value) {
return Math.pow(value, 2);
}

// Example of an instance method using a field
@CodeReflection
private double myFunctionWithFieldAccess() {
return Math.pow(this.value, 2);
}

static void main(String[] args) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The main method should be public as per standard Java conventions. It should also declare that it throws NoSuchMethodException to handle cases where getDeclaredMethod fails, which is a safer approach than what is currently implemented.

Suggested change
static void main(String[] args) {
public static void main(String[] args) throws NoSuchMethodException {

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add public modifier to main method

The main method should be public for standard Java execution.

-    static void main(String[] args) {
+    public static void main(String[] args) {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
static void main(String[] args) {
public static void main(String[] args) {
🤖 Prompt for AI Agents
In HelloCodeReflection.java at line 76, the main method is missing the public
modifier, which is required for standard Java execution. Add the public keyword
before static to make the method signature public static void main(String[]
args).


System.out.println("Hello Code Reflection!");

HelloCodeReflection obj = new HelloCodeReflection(5);

Optional<Method> myFunction = Stream.of(HelloCodeReflection.class.getDeclaredMethods())
.filter(m -> m.getName().equals("myFunction"))
.findFirst();

Method m = myFunction.get();
Comment on lines +82 to +86

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Retrieving the method myFunction using a stream is verbose and the subsequent .get() call is unsafe as it can throw a NoSuchElementException. It's better to use Class.getDeclaredMethod(), which is more direct and makes error handling explicit with a checked NoSuchMethodException.

        Method m = HelloCodeReflection.class.getDeclaredMethod("myFunction", int.class);

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add null check before calling get() on Optional

While the filter should ensure the Optional is present, it's safer to check explicitly.

-        Method m = myFunction.get();
+        Method m = myFunction.orElseThrow(() -> 
+            new IllegalStateException("Method 'myFunction' not found"));
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Method m = myFunction.get();
Method m = myFunction.orElseThrow(() ->
new IllegalStateException("Method 'myFunction' not found"));
🤖 Prompt for AI Agents
In HelloCodeReflection.java at line 86, add an explicit null check or
isPresent() check before calling get() on the Optional myFunction to avoid
potential NoSuchElementException. Modify the code to verify the Optional
contains a value before invoking get(), ensuring safer access.


// Obtain the code model for the annotated method
CoreOp.FuncOp codeModel = Op.ofMethod(m).get();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The use of .get() on an Optional is unsafe and can lead to a NoSuchElementException if the optional is empty. It's better to use methods like orElseThrow() to provide better error handling or context, making the code more robust.

        CoreOp.FuncOp codeModel = Op.ofMethod(m).orElseThrow();

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Handle potential empty Optional from Op.ofMethod

The Op.ofMethod(m).get() could return an empty Optional if the method is not annotated with @codereflection.

-        CoreOp.FuncOp codeModel = Op.ofMethod(m).get();
+        CoreOp.FuncOp codeModel = Op.ofMethod(m)
+            .orElseThrow(() -> new IllegalStateException("Failed to obtain code model for method: " + m.getName()));
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
CoreOp.FuncOp codeModel = Op.ofMethod(m).get();
CoreOp.FuncOp codeModel = Op.ofMethod(m)
.orElseThrow(() -> new IllegalStateException("Failed to obtain code model for method: " + m.getName()));
🤖 Prompt for AI Agents
In HelloCodeReflection.java at line 89, the call to Op.ofMethod(m).get() assumes
the Optional is always present, but it can be empty if the method lacks the
@CodeReflection annotation. Modify the code to check if the Optional is present
before calling get(), and handle the empty case appropriately, such as skipping
processing or logging a warning, to avoid NoSuchElementException.


// Print the code model of the annotated method
String codeModelString = codeModel.toText();
System.out.println(codeModelString);

// Transform the code model to an SSA representation
CoreOp.FuncOp ssaCodeModel = SSA.transform(codeModel);
System.out.println("SSA Representation of a code model");
System.out.println(ssaCodeModel.toText());

// Evaluate a code model
// because it is an instance method, the first parameter refers to `this`.
var result = Interpreter.invoke(MethodHandles.lookup(), ssaCodeModel, obj, 10);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Arbitrary Code Execution via Interpreter

The code uses the Interpreter to execute dynamically transformed code without proper validation. While the example itself is controlled, this pattern could be dangerous if extended to execute untrusted or user-influenced code models. The Interpreter.invoke() method effectively allows arbitrary code execution within the JVM, which could be exploited if the code model being executed comes from or is influenced by untrusted sources.

Suggested change
var result = Interpreter.invoke(MethodHandles.lookup(), ssaCodeModel, obj, 10);
// Add safety validation before executing code with Interpreter
if (validateCodeModel(ssaCodeModel)) {
var result = Interpreter.invoke(MethodHandles.lookup(), ssaCodeModel, obj, 10);
System.out.println("Evaluate a code model");
System.out.println(result);
} else {
System.err.println("Code model validation failed: execution aborted");
}
// Add this validation method
private static boolean validateCodeModel(CoreOp.FuncOp model) {
// Implement validation logic to ensure the code model is safe to execute
// For example, check for dangerous operations or patterns
return true; // Replace with actual validation logic
}
Standards
  • CWE-95
  • A08:2021-Software and Data Integrity Failures

System.out.println("Evaluate a code model");
System.out.println(result);

// Obtain parameters to the method
Block.Parameter _this = ssaCodeModel.body().entryBlock().parameters().get(0);
System.out.println("First parameter: " + _this);
Block.Parameter _second = ssaCodeModel.body().entryBlock().parameters().get(1);
System.out.println("Second parameter: " + _second);

// Another way to print a code model, traversing each element until we reach the parent
codeModel.traverse(null, (acc, codeElement) -> {
int depth = 0;
CodeElement<?, ?> parent = codeElement;
while ((parent = parent.parent()) != null) {
depth++;
}
System.out.println(" ".repeat(depth) + codeElement.getClass());
return acc;
});
}
}
263 changes: 263 additions & 0 deletions MathOptimizer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,263 @@
/*
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Incorrect Year Copyright

Copyright year 2025 is in the future. This creates a legally incorrect copyright statement that could affect licensing validity and create confusion about code origin date.

Suggested change
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
Standards
  • Business-Rule-Validation
  • Logic-Verification-Accuracy

* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package oracle.code.samples;

import jdk.incubator.code.Block;
import jdk.incubator.code.CodeReflection;
import jdk.incubator.code.CopyContext;
import jdk.incubator.code.Location;
import jdk.incubator.code.Op;
import jdk.incubator.code.OpTransformer;
import jdk.incubator.code.TypeElement;
import jdk.incubator.code.Value;
import jdk.incubator.code.dialect.core.CoreOp;
import jdk.incubator.code.dialect.java.JavaOp;
import jdk.incubator.code.dialect.java.JavaType;
import jdk.incubator.code.dialect.java.MethodRef;
import jdk.incubator.code.interpreter.Interpreter;

import java.lang.invoke.MethodHandles;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;

/**
* Simple example of how to use the code reflection API.
*
* <p>
* This example replaces a math function Math.pow with an optimized function using code transforms
* from the code-reflection API. The optimized function can be applied only under certain conditions.
* </p>
*
* <p>
* Optimizations:
* 1) Replace Pow(x, y) when x == 1 to 1 << y, if only if the parameter y is an integer.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The comment states that the optimization is for Pow(x, y) when x == 1. However, the implementation in myFunction and the check in inspectParameter are for x == 2. The comment should be updated to reflect the actual implementation.

Suggested change
* 1) Replace Pow(x, y) when x == 1 to 1 << y, if only if the parameter y is an integer.
* 1) Replace Pow(x, y) when x == 2 to 1 << y, if only if the parameter y is an integer.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix incorrect optimization description

The documentation states "when x == 1" but the code actually checks for x == 2.

- * 1) Replace Pow(x, y) when x == 1 to 1 << y, if only if the parameter y is an integer.
+ * 1) Replace Pow(x, y) when x == 2 to 1 << y, if only if the parameter y is an integer.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
* 1) Replace Pow(x, y) when x == 1 to 1 << y, if only if the parameter y is an integer.
* 1) Replace Pow(x, y) when x == 2 to 1 << y, if only if the parameter y is an integer.
🤖 Prompt for AI Agents
In MathOptimizer.java at line 58, the documentation incorrectly states the
optimization applies when x == 1, but the code checks for x == 2. Update the
documentation to correctly reflect the condition checked in the code, changing
"when x == 1" to "when x == 2" to ensure consistency between the comment and the
implementation.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Incorrect Optimization Logic

Comment states optimization replaces Math.pow(1, y) with 1 << y, but implementation actually optimizes Math.pow(2, y). Pow(1, y) always equals 1 regardless of y, while 1 << y gives incorrect results. This creates a logical contradiction.

Suggested change
* 1) Replace Pow(x, y) when x == 1 to 1 << y, if only if the parameter y is an integer.
* 1) Replace Pow(x, y) when x == 2 to 1 << y, if only if the parameter y is an integer.
Standards
  • Documentation-Accuracy
  • Logic-Verification-Consistency

* 2) Replace Pow(x, y) when y == 2 to x * x.
* </p>
*
* <p>
* Babylon repository: {@see <a href="https://github.com/openjdk/babylon/tree/code-reflection">link</a>}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix JavaDoc syntax error

Same issue as in HelloCodeReflection.java.

- *     Babylon repository: {@see <a href="https://github.com/openjdk/babylon/tree/code-reflection">link</a>}
+ *     Babylon repository: @see <a href="https://github.com/openjdk/babylon/tree/code-reflection">link</a>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
* Babylon repository: {@see <a href="https://github.com/openjdk/babylon/tree/code-reflection">link</a>}
* Babylon repository: @see <a href="https://github.com/openjdk/babylon/tree/code-reflection">link</a>
🤖 Prompt for AI Agents
In MathOptimizer.java at line 63, the JavaDoc syntax for the @see tag is
incorrect. Replace {@see <a href="...">link</a>} with the proper JavaDoc @see
syntax, which should be either @see URL or @see fully.qualified.ClassName,
without HTML tags. Correct the syntax to conform to standard JavaDoc
conventions.

* </p>
*
* <p>
* How to run?
* <code>
* java --enable-preview -cp target/crsamples-1.0-SNAPSHOT.jar oracle.code.samples.MathOptimizer
* </code>
* </p>:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

There is a stray colon at the end of the Javadoc paragraph tag.

Suggested change
* </p>:
* </p>

*/
public class MathOptimizer {

@CodeReflection
private static double myFunction(int value) {
return Math.pow(2, value);
}

// if pow(2, x), then substitute for this function
// We could apply this function if, at runtime, user pass int values to the pow function
// Thus, we narrow the result type from 8 bytes (double) to 4 bytes (INT).
private static int functionShift(int val) {
return 1 << val;
}

// if pow(x, 2) then substitute for this function
private static double functionMult(double x) {
return x * x;
}

private static final MethodRef MY_SHIFT_FUNCTION = MethodRef.method(MathOptimizer.class, "functionShift", int.class, int.class);

private static final MethodRef MY_MULT_FUNCTION = MethodRef.method(MathOptimizer.class, "functionMult", double.class, double.class);

// Analyze type methods: taken from example of String Concat Transformer to traverse the tree.
static boolean analyseType(Block.Builder block, JavaOp.ConvOp cz, JavaType typeToMatch) {
return analyseType(block, cz.operands().get(0), typeToMatch);
}

static boolean analyseType(Block.Builder block, Value v, JavaType typeToMatch) {
// Maybe there is an utility already to do tree traversal
if (v instanceof Op.Result r && r.op() instanceof JavaOp.ConvOp conv) {
// Node of tree, recursively traverse the operands
return analyseType(block, conv, typeToMatch);
} else {
// Leaf of tree: analyze type
TypeElement type = v.type();
return type.equals(typeToMatch);
}
}

static void main(String[] args) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The main method should be public as per standard Java conventions. It should also declare that it throws NoSuchMethodException to handle cases where getDeclaredMethod fails, which is a safer approach than what is currently implemented.

Suggested change
static void main(String[] args) {
public static void main(String[] args) throws NoSuchMethodException {

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add public modifier to main method

The main method should be public for standard Java execution.

-    static void main(String[] args) {
+    public static void main(String[] args) {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
static void main(String[] args) {
public static void main(String[] args) {
🤖 Prompt for AI Agents
In MathOptimizer.java at line 113, the main method is missing the public
modifier. Change the method declaration from static void main(String[] args) to
public static void main(String[] args) to ensure it is accessible for standard
Java execution.


Optional<Method> myFunction = Stream.of(MathOptimizer.class.getDeclaredMethods())
.filter(m -> m.getName().equals("myFunction"))
.findFirst();

Method myMathMethod = myFunction.get();
Comment on lines +115 to +119

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Retrieving the method myFunction using Stream.filter is verbose and the subsequent .get() call is unsafe. It can throw NoSuchElementException if the method is not found. Using Class.getDeclaredMethod() is more direct, efficient, and safer.

        Method myMathMethod = MathOptimizer.class.getDeclaredMethod("myFunction", int.class);

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add null check for Optional

-        Method myMathMethod = myFunction.get();
+        Method myMathMethod = myFunction.orElseThrow(() -> 
+            new IllegalStateException("Method 'myFunction' not found"));
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Method myMathMethod = myFunction.get();
Method myMathMethod = myFunction.orElseThrow(() ->
new IllegalStateException("Method 'myFunction' not found"));
🤖 Prompt for AI Agents
In MathOptimizer.java at line 119, the code retrieves a Method object from an
Optional without checking if it is present. Add a null check or use Optional's
isPresent() method before calling get() to avoid NoSuchElementException. Handle
the case where the Optional is empty appropriately, such as by logging an error
or providing a fallback.


// Obtain the code model for the annotated method
CoreOp.FuncOp codeModel = Op.ofMethod(myMathMethod).get();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The use of .get() on an Optional is unsafe and can lead to a NoSuchElementException if the optional is empty. It's better to use methods like orElseThrow() to provide better error handling or context.

        CoreOp.FuncOp codeModel = Op.ofMethod(myMathMethod).orElseThrow();

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Handle potential empty Optional from Op.ofMethod

-        CoreOp.FuncOp codeModel = Op.ofMethod(myMathMethod).get();
+        CoreOp.FuncOp codeModel = Op.ofMethod(myMathMethod)
+            .orElseThrow(() -> new IllegalStateException("Failed to obtain code model for method: " + myMathMethod.getName()));
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
CoreOp.FuncOp codeModel = Op.ofMethod(myMathMethod).get();
CoreOp.FuncOp codeModel = Op.ofMethod(myMathMethod)
.orElseThrow(() -> new IllegalStateException("Failed to obtain code model for method: " + myMathMethod.getName()));
🤖 Prompt for AI Agents
In MathOptimizer.java at line 122, the code calls
Op.ofMethod(myMathMethod).get() without checking if the Optional is present,
which can cause a NoSuchElementException if empty. Modify the code to first
check if the Optional returned by Op.ofMethod(myMathMethod) is present before
calling get(), and handle the empty case appropriately, such as throwing a clear
exception or providing a fallback.

System.out.println(codeModel.toText());

System.out.println("\nLet's transform the code");
codeModel = codeModel.transform(CopyContext.create(), (blockBuilder, op) -> {
switch (op) {
case JavaOp.InvokeOp invokeOp when whenIsMathPowFunction(invokeOp) -> {
// The idea here is to create a new JavaOp.invoke with the optimization and replace it.
List<Value> operands = blockBuilder.context().getValues(op.operands());

// Analyse second operand of the Math.pow(x, y).
// if the x == 2, and both are integers, then we can optimize the function using bitwise operations
// pow(2, y) replace with (1 << y)
Value operand = operands.getFirst(); // obtain the first parameter
// inspect if the base (as in pow(base, exp) is value 2
boolean canApplyBitShift = inspectParameter(operand, 2);
if (canApplyBitShift) {
// We also need to inspect types. We can apply this optimization
// if the exp type is also an integer.
boolean isIntType = analyseType(blockBuilder, operands.get(1), JavaType.INT);
if (!isIntType) {
canApplyBitShift = false;
}
}

// If the conditions to apply the first optimization failed, we try the second optimization
// if types are not int, and base is not 2.
// pow(x, 2) => replace with x * x
boolean canApplyMultiplication = false;
if (!canApplyBitShift) {
// inspect if exp (as in pow(base, exp) is value 2
canApplyMultiplication = inspectParameter(operands.get(1), 2);
}

if (canApplyBitShift) {
// Narrow type from DOUBLE to INT for the input parameter of the new function.
Op.Result op2 = blockBuilder.op(JavaOp.conv(JavaType.INT, operands.get(1)));
List<Value> newOperandList = new ArrayList<>();
newOperandList.add(op2);
Comment on lines +158 to +160
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Array Reallocation

Creating a new ArrayList for a single element causes unnecessary allocation overhead. For small, fixed-size collections, using List.of() provides better performance with zero reallocation cost.

Suggested change
Op.Result op2 = blockBuilder.op(JavaOp.conv(JavaType.INT, operands.get(1)));
List<Value> newOperandList = new ArrayList<>();
newOperandList.add(op2);
Op.Result op2 = blockBuilder.op(JavaOp.conv(JavaType.INT, operands.get(1)));
List<Value> newOperandList = List.of(op2);
Standards
  • ISO-IEC-25010-Performance-Resource-Utilization
  • Algorithm-Opt-Memory-Allocation
  • Java-Collections-Performance


// Create a new invoke with the optimised method
JavaOp.InvokeOp newInvoke = JavaOp.invoke(MY_SHIFT_FUNCTION, newOperandList);
// Copy the original location info to the new invoke
newInvoke.setLocation(invokeOp.location());

// Replace the invoke node with the new optimized invoke
Op.Result newResult = blockBuilder.op(newInvoke);
blockBuilder.context().mapValue(invokeOp.result(), newResult);

} else if (canApplyMultiplication) {
// Adapt the parameters to the new function. We only need the first
// parameter from the initial parameter list - pow(x, 2) -
// Thus, we copy parameter x into a new list and pass it to the new
// invoke function.
List<Value> newOperandList2 = new ArrayList<>();
newOperandList2.add(operands.get(0));
Comment on lines +176 to +177
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Repeated ArrayList Creation

Creating a new ArrayList for a single element causes unnecessary allocation. For fixed-size collections with known elements, List.of() provides better performance with zero allocation overhead.

Suggested change
List<Value> newOperandList2 = new ArrayList<>();
newOperandList2.add(operands.get(0));
List<Value> newOperandList2 = List.of(operands.get(0));
Standards
  • ISO-IEC-25010-Performance-Resource-Utilization
  • Algorithm-Opt-Memory-Allocation
  • Java-Collections-Performance


// Create a new invoke function with the optimised method
JavaOp.InvokeOp newInvoke = JavaOp.invoke(MY_MULT_FUNCTION, newOperandList2);
// Copy the location info to the new invoke
newInvoke.setLocation(invokeOp.location());

// Replace the invoke node with the new optimized invoke
Op.Result newResult = blockBuilder.op(newInvoke);
blockBuilder.context().mapValue(invokeOp.result(), newResult);

} else {
// ignore the transformation
blockBuilder.op(op);
}
}
default -> blockBuilder.op(op);
}
return blockBuilder;
});

System.out.println("AFTER TRANSFORM: ");
System.out.println(codeModel.toText());
codeModel = codeModel.transform(OpTransformer.LOWERING_TRANSFORMER);
System.out.println("After Lowering: ");
System.out.println(codeModel.toText());

System.out.println("\nEvaluate");
// The Interpreter Invoke should launch new exceptions
var result = Interpreter.invoke(MethodHandles.lookup(), codeModel, 10);
Comment on lines +123 to +206
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unsafe Code Transformation and Execution

The code transforms a method at runtime and executes it using the Interpreter without proper validation. This pattern could be dangerous if applied to untrusted code or if the transformation logic contains flaws. The current implementation substitutes Math.pow() with custom functions that could potentially be exploited if user input were involved in determining transformation rules. While this example is controlled, it demonstrates a pattern that could lead to arbitrary code execution if misused in a production environment.

Suggested change
System.out.println(codeModel.toText());
System.out.println("\nLet's transform the code");
codeModel = codeModel.transform(CopyContext.create(), (blockBuilder, op) -> {
switch (op) {
case JavaOp.InvokeOp invokeOp when whenIsMathPowFunction(invokeOp) -> {
// The idea here is to create a new JavaOp.invoke with the optimization and replace it.
List<Value> operands = blockBuilder.context().getValues(op.operands());
// Analyse second operand of the Math.pow(x, y).
// if the x == 2, and both are integers, then we can optimize the function using bitwise operations
// pow(2, y) replace with (1 << y)
Value operand = operands.getFirst(); // obtain the first parameter
// inspect if the base (as in pow(base, exp) is value 2
boolean canApplyBitShift = inspectParameter(operand, 2);
if (canApplyBitShift) {
// We also need to inspect types. We can apply this optimization
// if the exp type is also an integer.
boolean isIntType = analyseType(blockBuilder, operands.get(1), JavaType.INT);
if (!isIntType) {
canApplyBitShift = false;
}
}
// If the conditions to apply the first optimization failed, we try the second optimization
// if types are not int, and base is not 2.
// pow(x, 2) => replace with x * x
boolean canApplyMultiplication = false;
if (!canApplyBitShift) {
// inspect if exp (as in pow(base, exp) is value 2
canApplyMultiplication = inspectParameter(operands.get(1), 2);
}
if (canApplyBitShift) {
// Narrow type from DOUBLE to INT for the input parameter of the new function.
Op.Result op2 = blockBuilder.op(JavaOp.conv(JavaType.INT, operands.get(1)));
List<Value> newOperandList = new ArrayList<>();
newOperandList.add(op2);
// Create a new invoke with the optimised method
JavaOp.InvokeOp newInvoke = JavaOp.invoke(MY_SHIFT_FUNCTION, newOperandList);
// Copy the original location info to the new invoke
newInvoke.setLocation(invokeOp.location());
// Replace the invoke node with the new optimized invoke
Op.Result newResult = blockBuilder.op(newInvoke);
blockBuilder.context().mapValue(invokeOp.result(), newResult);
} else if (canApplyMultiplication) {
// Adapt the parameters to the new function. We only need the first
// parameter from the initial parameter list - pow(x, 2) -
// Thus, we copy parameter x into a new list and pass it to the new
// invoke function.
List<Value> newOperandList2 = new ArrayList<>();
newOperandList2.add(operands.get(0));
// Create a new invoke function with the optimised method
JavaOp.InvokeOp newInvoke = JavaOp.invoke(MY_MULT_FUNCTION, newOperandList2);
// Copy the location info to the new invoke
newInvoke.setLocation(invokeOp.location());
// Replace the invoke node with the new optimized invoke
Op.Result newResult = blockBuilder.op(newInvoke);
blockBuilder.context().mapValue(invokeOp.result(), newResult);
} else {
// ignore the transformation
blockBuilder.op(op);
}
}
default -> blockBuilder.op(op);
}
return blockBuilder;
});
System.out.println("AFTER TRANSFORM: ");
System.out.println(codeModel.toText());
codeModel = codeModel.transform(OpTransformer.LOWERING_TRANSFORMER);
System.out.println("After Lowering: ");
System.out.println(codeModel.toText());
System.out.println("\nEvaluate");
// The Interpreter Invoke should launch new exceptions
var result = Interpreter.invoke(MethodHandles.lookup(), codeModel, 10);
// Add security validation before executing transformed code
// Verify the transformation doesn't introduce security risks
boolean isTransformationSafe = validateTransformation(codeModel);
if (isTransformationSafe) {
var result = Interpreter.invoke(MethodHandles.lookup(), codeModel, 10);
System.out.println(result);
} else {
System.err.println("Transformation validation failed: potentially unsafe code");
}
// Add this method to validate transformations
private static boolean validateTransformation(CoreOp.FuncOp model) {
// Implement validation logic to ensure transformations are safe
// Check for potentially dangerous operations, etc.
return true; // Replace with actual validation
}
Standards
  • CWE-94
  • A08:2021-Software and Data Integrity Failures

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unsafe Deserialization Risk

Interpreter.invoke executes transformed code without validation. Malicious code transformations could lead to arbitrary code execution if input is untrusted.

Suggested change
var result = Interpreter.invoke(MethodHandles.lookup(), codeModel, 10);
// Validate transformed code before execution
validateTransformedCode(codeModel);
var result = Interpreter.invoke(MethodHandles.lookup(), codeModel, 10);
Standards
  • CWE-502
  • OWASP-A08

System.out.println(result);

// Select invocation calls and display the lines
System.out.println("\nPlaying with Traverse");
codeModel.traverse(null, (map, op) -> {
if (op instanceof JavaOp.InvokeOp invokeOp) {
System.out.println("Function Name: " + invokeOp.invokeDescriptor().name());

// Maybe Location should throw a new exception instead of the NPE,
// since it is possible we don't have a location after a transformation has been done.
Location location = invokeOp.location();
if (location != null) {
int line = location.line();
System.out.println("Line " + line);
System.out.println("Class: " + invokeOp.getClass());
// Detect Math::pow
boolean contains = invokeOp.invokeDescriptor().equals(JAVA_LANG_MATH_POW);
if (contains) {
System.out.println("Method: " + invokeOp.invokeDescriptor().name());
}
} else {
System.out.println("[WARNING] Location is null");
}
Comment on lines +217 to +229
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Null Location Check

Location null check exists but invokeDescriptor() is called without null check after transformation. If location is null but invokeDescriptor is also null, NullPointerException could occur.

Suggested change
Location location = invokeOp.location();
if (location != null) {
int line = location.line();
System.out.println("Line " + line);
System.out.println("Class: " + invokeOp.getClass());
// Detect Math::pow
boolean contains = invokeOp.invokeDescriptor().equals(JAVA_LANG_MATH_POW);
if (contains) {
System.out.println("Method: " + invokeOp.invokeDescriptor().name());
}
} else {
System.out.println("[WARNING] Location is null");
}
Location location = invokeOp.location();
if (location != null) {
int line = location.line();
System.out.println("Line " + line);
System.out.println("Class: " + invokeOp.getClass());
// Detect Math::pow
if (invokeOp.invokeDescriptor() != null) {
boolean contains = invokeOp.invokeDescriptor().equals(JAVA_LANG_MATH_POW);
if (contains) {
System.out.println("Method: " + invokeOp.invokeDescriptor().name());
}
}
} else {
System.out.println("[WARNING] Location is null");
}
Standards
  • ISO-IEC-25010-Reliability-Fault-Tolerance
  • ISO-IEC-25010-Functional-Correctness-Appropriateness
  • DbC-Defensive-Programming
  • SRE-Error-Handling

}
return map;
});
}

// It could be a better way of doing the following.
// Goal: obtain and check the value of the function parameters.
private static boolean inspectParameter(Value operand, final int value) {
final Boolean[] isMultipliedByTwo = new Boolean[] { false };
if (operand instanceof Op.Result res) {
if (res.op() instanceof JavaOp.ConvOp convOp) {
convOp.operands().forEach(v -> {
if (v instanceof Op.Result res2) {
if (res2.op() instanceof CoreOp.ConstantOp constantOp) {
if (constantOp.value() instanceof Integer parameter) {
if (parameter.intValue() == value) {
// Transformation is valid
isMultipliedByTwo[0] = true;
}
}
}
}
});
}
}
Comment on lines +239 to +254
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deep Nesting

Excessive nesting creates cognitive complexity and reduces maintainability. Five levels of nesting make the code difficult to follow and modify. This pattern makes future extensions error-prone.

Suggested change
if (operand instanceof Op.Result res) {
if (res.op() instanceof JavaOp.ConvOp convOp) {
convOp.operands().forEach(v -> {
if (v instanceof Op.Result res2) {
if (res2.op() instanceof CoreOp.ConstantOp constantOp) {
if (constantOp.value() instanceof Integer parameter) {
if (parameter.intValue() == value) {
// Transformation is valid
isMultipliedByTwo[0] = true;
}
}
}
}
});
}
}
private static boolean inspectParameter(Value operand, final int value) {
if (!(operand instanceof Op.Result res)) {
return false;
}
if (!(res.op() instanceof JavaOp.ConvOp convOp)) {
return false;
}
return convOp.operands().stream().anyMatch(v -> isMatchingConstant(v, value));
}
private static boolean isMatchingConstant(Value v, int expectedValue) {
if (!(v instanceof Op.Result res2)) {
return false;
}
if (!(res2.op() instanceof CoreOp.ConstantOp constantOp)) {
return false;
}
if (!(constantOp.value() instanceof Integer parameter)) {
return false;
}
return parameter.intValue() == expectedValue;
}
Standards
  • Clean-Code-Functions
  • Clean-Code-Complexity
  • Refactoring-Extract-Method

return isMultipliedByTwo[0];
Comment on lines +238 to +255
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Array Access Safety

Single-element array used for lambda capture could cause thread-safety issues in concurrent environments. Boolean array mutation is not atomic and could lead to race conditions.

Suggested change
final Boolean[] isMultipliedByTwo = new Boolean[] { false };
if (operand instanceof Op.Result res) {
if (res.op() instanceof JavaOp.ConvOp convOp) {
convOp.operands().forEach(v -> {
if (v instanceof Op.Result res2) {
if (res2.op() instanceof CoreOp.ConstantOp constantOp) {
if (constantOp.value() instanceof Integer parameter) {
if (parameter.intValue() == value) {
// Transformation is valid
isMultipliedByTwo[0] = true;
}
}
}
}
});
}
}
return isMultipliedByTwo[0];
import java.util.concurrent.atomic.AtomicBoolean;
private static boolean inspectParameter(Value operand, final int value) {
final AtomicBoolean isMultipliedByTwo = new AtomicBoolean(false);
if (operand instanceof Op.Result res) {
if (res.op() instanceof JavaOp.ConvOp convOp) {
convOp.operands().forEach(v -> {
if (v instanceof Op.Result res2) {
if (res2.op() instanceof CoreOp.ConstantOp constantOp) {
if (constantOp.value() instanceof Integer parameter) {
if (parameter.intValue() == value) {
// Transformation is valid
isMultipliedByTwo.set(true);
}
}
}
}
});
}
}
return isMultipliedByTwo.get();
}
Standards
  • ISO-IEC-25010-Reliability-Maturity
  • ISO-IEC-25010-Functional-Correctness-Appropriateness
  • DbC-Thread-Safety
  • SRE-Concurrency-Safety

}
Comment on lines +237 to +256

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The inspectParameter method is overly complex and brittle. Using a single-element array Boolean[] to simulate a mutable boolean is a code smell and makes the logic hard to follow. The current implementation also doesn't correctly traverse nested ConvOp nodes. The method can be simplified significantly by using recursion, which will make it more readable, maintainable, and correct.

    private static boolean inspectParameter(Value operand, final int value) {
        if (operand instanceof Op.Result res) {
            if (res.op() instanceof JavaOp.ConvOp convOp) {
                // This is a conversion, inspect the operand being converted
                if (!convOp.operands().isEmpty()) {
                    return inspectParameter(convOp.operands().get(0), value);
                }
            } else if (res.op() instanceof CoreOp.ConstantOp constantOp) {
                if (constantOp.value() instanceof Integer parameter) {
                    return parameter.intValue() == value;
                }
            }
        }
        return false;
    }


static final MethodRef JAVA_LANG_MATH_POW = MethodRef.method(Math.class, "pow", double.class, double.class, double.class);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The MethodRef for Math.pow is incorrect. The pow method in java.lang.Math has the signature pow(double, double), taking two double arguments. You have provided three double.class arguments. This will cause the whenIsMathPowFunction check to always fail, preventing any optimization from being applied.

    static final MethodRef JAVA_LANG_MATH_POW = MethodRef.method(Math.class, "pow", double.class, double.class);


private static boolean whenIsMathPowFunction(JavaOp.InvokeOp invokeOp) {
return invokeOp.invokeDescriptor().equals(JAVA_LANG_MATH_POW);
}
}