Skip to content

Add additional version of DynComp for Java 24 - #685

Open
markro49 wants to merge 323 commits into
codespecs:masterfrom
markro49:java-24-dcomp-3
Open

Add additional version of DynComp for Java 24#685
markro49 wants to merge 323 commits into
codespecs:masterfrom
markro49:java-24-dcomp-3

Conversation

@markro49

@markro49 markro49 commented Oct 3, 2025

Copy link
Copy Markdown
Contributor

No description provided.

markro49 and others added 30 commits July 23, 2025 14:33
remove IntrinsicCandidate annotations
clean up many UNDONEs
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In @java/daikon/chicory/Instrument.java:
- Around line 95-131: The file Instrument contains several commented-out type
descriptor fields (e.g., CD_Class, CD_Throwable, CD_boolean, CD_byte, CD_char,
CD_double, CD_float, CD_long, CD_short) surrounding the active descriptors
CD_Object, CD_String, CD_int, CD_void, and CD_Object_array; remove the unused
commented-out declarations to clean up the class or, if any of those types are
actually required, restore them by uncommenting and using the corresponding
symbols (e.g., CD_Class, CD_Throwable, CD_boolean) where needed. After editing,
ensure Instrument still compiles and run existing tests to confirm no behavior
changes, and update any related Javadoc/comments to reflect the retained
descriptors.

In @java/daikon/dcomp/BuildJDK24.java:
- Around line 82-84: The field inst24 currently suppresses nullness warnings
with a TODO; replace the suppression by explicitly encoding the initialization
contract: declare private static
@org.checkerframework.checker.nullness.qual.MonotonicNonNull
daikon.dcomp.Instrument24 inst24 = null and keep the assignment in main(), or
alternatively initialize inst24 in a static initializer; also add a brief
Javadoc on class BuildJDK24 explaining that main() initializes inst24 before use
and/or add an explicit runtime check (Objects.requireNonNull(inst24)) where it’s
first used to make the contract explicit.
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c415c8c and 293d987.

📒 Files selected for processing (7)
  • Makefile
  • java/daikon/chicory/Instrument.java
  • java/daikon/chicory/Runtime.java
  • java/daikon/dcomp/BuildJDK24.java
  • java/daikon/dcomp/ClassGen24.java
  • java/daikon/dcomp/DCInstrument.java
  • java/daikon/dcomp/DCInstrument24.java
🧰 Additional context used
🧬 Code graph analysis (1)
java/daikon/dcomp/BuildJDK24.java (3)
java/daikon/chicory/ClassInfo.java (1)
  • ClassInfo (20-154)
java/daikon/chicory/Runtime.java (1)
  • SuppressWarnings (51-1199)
java/daikon/chicory/MethodInfo.java (1)
  • SuppressWarnings (22-277)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
  • GitHub Check: codespecs.daikon (typecheck_latest_part1_ubuntu_jdk25)
  • GitHub Check: codespecs.daikon (typecheck_latest_part2_ubuntu_jdk25)
  • GitHub Check: codespecs.daikon (typecheck_latest_part3_ubuntu_jdk25)
  • GitHub Check: codespecs.daikon (typecheck_bundled_part3_ubuntu_jdk25)
  • GitHub Check: codespecs.daikon (typecheck_bundled_part2_ubuntu_jdk25)
  • GitHub Check: codespecs.daikon (misc_ubuntu_jdk25)
  • GitHub Check: codespecs.daikon (typecheck_bundled_part1_ubuntu_jdk25)
  • GitHub Check: codespecs.daikon (quick_ubuntu_jdk25)
  • GitHub Check: codespecs.daikon (kvasir_ubuntu_jdk25)
  • GitHub Check: codespecs.daikon (nonquick_ubuntu_jdk25)
  • GitHub Check: codespecs.daikon (nontxt_ubuntu_jdk25)
🔇 Additional comments (25)
Makefile (1)

754-804: LGTM! Output suppression improves build experience.

The addition of @ prefixes to suppress command echoing in update targets is a good UX improvement. These changes don't affect the logic or error handling of the commands.

java/daikon/chicory/Runtime.java (3)

44-44: LGTM! Required import for new helper methods.

The InternalForm annotation import is necessary for the new conversion methods added at lines 1175-1194.


539-555: Good fix: Error messages now properly go to stderr.

Routing error messages to System.err instead of System.out follows standard conventions and makes it easier to separate error output from normal program output.


1175-1194: LGTM! Useful utility methods with proper annotations.

These conversion helpers centralize standard name format transformations. The implementations are straightforward and correctly annotated with @BinaryName and @InternalForm.

java/daikon/chicory/Instrument.java (9)

224-230: Good improvement: More precise package checks.

Adding the trailing dot to the package prefix checks (lines 224, 227) ensures that only classes actually in those packages are matched, not classes with similar prefix names.


242-257: LGTM! Better error handling in debug output.

The renamed method (writeDebugClassFiles) is clearer, and the conditional stack trace printing (lines 252-254) prevents overwhelming output when not in debug mode.


280-283: Good defensive check for null className.

Adding a null check prevents potential NPEs when processing lambda-related classes that may not have conventional class names.


318-345: Improved error handling with conditional diagnostics.

The error handling at parse time (318-324) and instrumentation time (339-345) now provides clear error messages while only printing stack traces when debug mode is enabled. This is a good balance between diagnostics and noise reduction.


373-395: Static field handling is correct but note architectural limitation.

The code correctly stores constant static field values in classInfo.staticMap. The comment at lines 373-374 acknowledges that this should ideally be a method of ClassInfo, but can't be due to compatibility requirements with both Instrument.java and Instrument24.java. This is a reasonable pragmatic choice.


1178-1181: Nice refactoring using ArraysPlume utility.

Replacing manual array processing with ArraysPlume.mapArray makes the code more concise and idiomatic.


1190-1191: Better method name reflects behavior.

Renaming to create_method_info_if_instrumented makes it clear that this method may return null if the method should not be instrumented.


1268-1277: Variable renames improve clarity.

Renaming exit_locs to exit_line_numbers (line 1268) and last_line_number to prev_line_number (line 1276) makes the code more self-documenting.


1367-1380: Better method name for clarity.

Renaming isChicory to isChicoryClass makes the method's purpose clearer and is more consistent with naming conventions.

java/daikon/dcomp/BuildJDK24.java (7)

116-208: LGTM! Main method has good structure and error handling.

The main method properly handles two modes (specific class files vs. full JDK instrumentation), uses try-with-resources for file I/O, and includes appropriate progress reporting. The separation of concerns between the two modes is clear.


210-244: Good validation logic for Java home directory.

The check_java_home method provides thorough validation with clear error messages. Exiting the JVM on validation failures is appropriate for a build tool.


256-283: Verify resource management pattern for JarFile.

The comment at lines 261-262 states that the JarFile is intentionally not closed because input streams are saved for later reading. However, this pattern is risky:

  1. The JarFile remains open for the lifetime of the application
  2. If the JVM exits abnormally, the file handle may leak
  3. The input streams may become invalid if the underlying JarFile is garbage collected

Please verify that the input streams obtained from the JarFile remain valid when used in instrument_classes(). Consider either:

  • Closing the JarFile after reading all streams (and ensuring streams are cached/buffered)
  • Using try-with-resources and reading all class bytes into memory before closing
  • Documenting the resource management contract more explicitly

357-443: Good resource management in instrument_classes.

The method properly uses try-with-resources for InputStreams at lines 394-396 and 408-410, ensuring streams from class_stream_map are closed after reading. This addresses any resource leak concerns from the gather methods.


450-507: LGTM! Interface class generation uses modern APIs.

The creation of synthetic interface classes (DCompMarker, DCompInstrumented, etc.) uses the ClassFile API appropriately. The version calculation at line 497 (BcelUtil.javaVersion + 44) correctly computes the class file major version.


524-609: Well-structured instrumentation and error reporting.

The instrumentClassFile method includes helpful progress reporting (lines 565-571), and print_skipped_methods effectively separates known issues from new problems, making it easier for users to understand what needs attention.


285-349: No action needed. InputStreams created in gather_runtime_from_modules_directory() are properly closed in instrument_classes() using try-with-resources blocks (lines 394–395 and 408–409), consistent with the jar-based approach. This pattern is intentional and handles resource cleanup correctly.

Likely an incorrect or invalid review comment.

java/daikon/dcomp/ClassGen24.java (5)

20-68: Excellent class documentation and design rationale.

The javadoc clearly explains the purpose of ClassGen24 as an adapter to make the ClassFile API more similar to BCEL's ClassGen, facilitating code sharing between DCInstrument.java and DCInstrument24.java. The caching strategy for frequently-accessed fields is well-justified.


76-94: Constructor properly initializes all fields.

The constructor correctly caches immutable data and creates a mutable copy of the interface list (line 93) to support the addInterface() method. The comment at lines 91-92 explains this design choice.


101-111: LGTM! Proper interface addition with duplicate check.

The method correctly converts names (line 102), checks for duplicates (lines 103-107), and adds the interface via the constant pool (lines 108-110).


120-128: Method lookup is correct but uses linear search.

The containsMethod implementation correctly searches for a method by name and descriptor. The linear search (O(n)) should be fine given that most classes have a small number of methods. If performance becomes an issue with large classes, consider caching or using a Map.


195-202: Superclass handling for Object is documented.

The comments at lines 177-178 and 187-189 acknowledge that returning "java.lang.Object" for Object's superclass is "probably incorrect" but maintains consistency with BCEL's behavior. This is a reasonable choice for API compatibility, though it could be a source of bugs if not carefully handled by callers.

Comment on lines +95 to +131

/** "java.lang.Object". */
private static final ObjectType CD_Object = Type.OBJECT;

// /** Type for "java.lang.Class". */
// private static final ObjectType CD_Class = Type.CLASS;

/** Type for "java.lang.String". */
private static final ObjectType CD_String = Type.STRING;

// /** Type for "java.lang.Throwable". */
// protected static ObjectType CD_Throwable = new ObjectType("java.lang.Throwable");
// private static final ObjectType CD_Throwable = Type.THROWABLE;

// /** Type for "boolean". */
// private static final @InternedDistinct BasicType CD_boolean = Type.BOOLEAN;
// /** Type for "byte". */
// private static final @InternedDistinct BasicType CD_byte = Type.BYTE;
// /** Type for "char". */
// private static final @InternedDistinct BasicType CD_char = Type.CHAR;
// /** Type for "double". */
// private static final @InternedDistinct BasicType CD_double = Type.DOUBLE;
// /** Type for "float". */
// private static final @InternedDistinct BasicType CD_float = Type.FLOAT;
/** Type for "int". */
private static final @InternedDistinct BasicType CD_int = Type.INT;

// /** Type for "long". */
// private static final @InternedDistinct BasicType CD_long = Type.LONG;
// /** Type for "short". */
// private static final @InternedDistinct BasicType CD_short = Type.SHORT;
/** Type for "void". */
private static final @InternedDistinct BasicType CD_void = Type.VOID;

/** "java.lang.Object[]". */
protected static Type CD_Object_array = new ArrayType(CD_Object, 1);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider removing commented-out type descriptors.

The active type descriptors (CD_Object, CD_String, CD_int, CD_void, CD_Object_array) are well-defined and improve code clarity. However, the commented-out descriptors (lines 99-133) should either be removed if unused, or uncommented if needed.

🤖 Prompt for AI Agents
In @java/daikon/chicory/Instrument.java around lines 95 - 131, The file
Instrument contains several commented-out type descriptor fields (e.g.,
CD_Class, CD_Throwable, CD_boolean, CD_byte, CD_char, CD_double, CD_float,
CD_long, CD_short) surrounding the active descriptors CD_Object, CD_String,
CD_int, CD_void, and CD_Object_array; remove the unused commented-out
declarations to clean up the class or, if any of those types are actually
required, restore them by uncommenting and using the corresponding symbols
(e.g., CD_Class, CD_Throwable, CD_boolean) where needed. After editing, ensure
Instrument still compiles and run existing tests to confirm no behavior changes,
and update any related Javadoc/comments to reflect the retained descriptors.

Comment on lines +82 to +84
/** Allow BuildJDK24 to access outputDebugFiles. */
@SuppressWarnings("nullness:initialization.static.field.uninitialized") // TODO
private static daikon.dcomp.Instrument24 inst24;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Address the TODO for inst24 initialization.

The @SuppressWarnings("nullness:initialization.static.field.uninitialized") with a TODO comment suggests incomplete initialization handling. Since inst24 is initialized in main() at line 134 before use, this is currently safe, but consider documenting the initialization contract or using a different pattern to avoid the suppression.

🤖 Prompt for AI Agents
In @java/daikon/dcomp/BuildJDK24.java around lines 82 - 84, The field inst24
currently suppresses nullness warnings with a TODO; replace the suppression by
explicitly encoding the initialization contract: declare private static
@org.checkerframework.checker.nullness.qual.MonotonicNonNull
daikon.dcomp.Instrument24 inst24 = null and keep the assignment in main(), or
alternatively initialize inst24 in a static initializer; also add a brief
Javadoc on class BuildJDK24 explaining that main() initializes inst24 before use
and/or add an explicit runtime check (Objects.requireNonNull(inst24)) where it’s
first used to make the contract explicit.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@java/daikon/chicory/Runtime.java`:
- Around line 1086-1088: The comment about shadowJar troubleshooting in
Runtime.java should include a tracked-issue reference so it can be revisited;
update the note in the Runtime class (the existing shadowJar comment block) to
add a TODO with the issue tracker identifier or URL (e.g., "TODO: track
shadowJar fix in ISSUE-XXXX: <link>") and optionally include the date and owner,
so future maintainers can find and close the TODO when the shadowJar problem is
resolved.

In `@java/lib/build.gradle`:
- Line 3: The build is using Shadow plugin version "com.gradleup.shadow" 9.3.1
which requires Gradle 9.0+, so add a gradle-wrapper.properties file to pin the
Gradle distribution to 9.0 or newer and commit the wrapper files; specifically,
create/update the Gradle Wrapper configuration (so the project uses Gradle 9.0+)
and regenerate the wrapper by running the Gradle task that produces the wrapper
(e.g., the "wrapper" task) so the repo contains a gradle-wrapper.properties with
a distributionUrl pointing to a Gradle 9.0+ distribution and the corresponding
wrapper scripts/jar.

Comment on lines +1086 to +1088
// Eventually the code should use the library rather than copying its code.
// (As of 2026-01-10, I'm having trouble with the shadowJar plugin.)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider linking this note to a tracked issue.

The shadowJar troubleshooting note is useful; adding a TODO/issue reference would make it easier to revisit and remove once resolved.

🤖 Prompt for AI Agents
In `@java/daikon/chicory/Runtime.java` around lines 1086 - 1088, The comment about
shadowJar troubleshooting in Runtime.java should include a tracked-issue
reference so it can be revisited; update the note in the Runtime class (the
existing shadowJar comment block) to add a TODO with the issue tracker
identifier or URL (e.g., "TODO: track shadowJar fix in ISSUE-XXXX: <link>") and
optionally include the date and owner, so future maintainers can find and close
the TODO when the shadowJar problem is resolved.

Comment thread java/lib/build.gradle
plugins {
id("java")
id("com.gradleup.shadow").version("9.2.2")
id("com.gradleup.shadow").version("9.3.1")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find gradle-wrapper.properties to check Gradle version
fd -a gradle-wrapper.properties -x cat {}

Repository: codespecs/daikon

Length of output: 42


🌐 Web query:

Shadow Gradle plugin 9.3.1 minimum Gradle version requirements

💡 Result:

Shadow Gradle Plugin 9.3.1 (plugin id com.gradleup.shadow) requires Gradle 9.0 or newer (minimum). This is because Shadow 9.3.0+ has a min Gradle version of 9.0, and 9.3.1 is a patch release in that line. [1], [2]

(For completeness: Shadow 9.3.x also requires Java 17+.) [1]


🌐 Web query:

Shadow Gradle plugin 9.3.1 breaking changes release notes

💡 Result:

Shadow Gradle plugin 9.3.1 (released 2026-01-06) is a patch release with no documented breaking changes. The published release notes list only one fix:

  • Fixed: “Use ASM from jdependency embedded” to avoid potential classpath conflicts with other plugins that also use ASM. [1]

If you’re upgrading to 9.3.x from earlier Shadow versions, note that Shadow 9.3.0+ requires Gradle 9.0+ and Java 17+ (this requirement is a potentially breaking upgrade constraint, but it’s not new in 9.3.1 specifically). [2]

Sources: [1] Shadow changelog (GradleUp) • [2] GradleUp/shadow README compatibility matrix


🏁 Script executed:

#!/bin/bash
# Find and read gradle-wrapper.properties explicitly
if [ -f "gradle-wrapper.properties" ]; then
  cat gradle-wrapper.properties
else
  # Search for it recursively
  find . -name "gradle-wrapper.properties" -type f -exec cat {} \;
fi

Repository: codespecs/daikon

Length of output: 42


🏁 Script executed:

#!/bin/bash
# Also check for any gradle.properties or settings.gradle that might specify version
fd -a "gradle.properties|settings.gradle" -x sh -c 'echo "=== {} ===" && head -20 {}'

Repository: codespecs/daikon

Length of output: 42


🏁 Script executed:

#!/bin/bash
# List repo structure
ls -la
# Check for common gradle locations
find . -maxdepth 3 -name "*gradle*" -type f 2>/dev/null | head -20

Repository: codespecs/daikon

Length of output: 1619


🏁 Script executed:

#!/bin/bash
# Check if gradle wrapper exists and list all gradle-related files
git ls-files | grep -i gradle | head -20

Repository: codespecs/daikon

Length of output: 81


🏁 Script executed:

#!/bin/bash
# Read the full build.gradle file
cat -n java/lib/build.gradle

Repository: codespecs/daikon

Length of output: 807


Add gradle-wrapper.properties to enforce Gradle 9.0+ (required by Shadow 9.3.1).

Shadow 9.3.1 requires Gradle 9.0 or newer. The repo lacks a gradle-wrapper.properties file to pin the Gradle version, which could cause build failures if developers or CI systems use older Gradle versions. Add a gradle-wrapper.properties file specifying Gradle 9.0 or later to ensure build reproducibility.

(Note: Shadow 9.3.1 is a patch release with no breaking changes—only an ASM classpath conflict fix.)

🤖 Prompt for AI Agents
In `@java/lib/build.gradle` at line 3, The build is using Shadow plugin version
"com.gradleup.shadow" 9.3.1 which requires Gradle 9.0+, so add a
gradle-wrapper.properties file to pin the Gradle distribution to 9.0 or newer
and commit the wrapper files; specifically, create/update the Gradle Wrapper
configuration (so the project uses Gradle 9.0+) and regenerate the wrapper by
running the Gradle task that produces the wrapper (e.g., the "wrapper" task) so
the repo contains a gradle-wrapper.properties with a distributionUrl pointing to
a Gradle 9.0+ distribution and the corresponding wrapper scripts/jar.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
java/Makefile (1)

51-60: ⚠️ Potential issue | 🟠 Major

Create BuildJDK25 instead of relying on BuildJDK24's runtime version detection for Java 25+.

Although BuildJDK24 uses runtime version detection (BcelUtil.javaVersion) to generate the correct classfile version (69) when run under Java 25, the current design is a temporary workaround that should be formalized. The Makefile comment "Temporary, since Java 24 is not a LTS release" is now stale—Java 25 is an LTS release. Instead of using BuildJDK24 for both Java 24 and Java 25+, create a BuildJDK25 class (following the pattern of BuildJDK24) and update the Makefile to set BuildJDKTool = BuildJDK25 when JAVA_RELEASE_NUMBER >= 25. This makes the intent explicit and avoids confusion about which build tool is responsible for which Java version.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@java/Makefile` around lines 51 - 60, Makefile currently reuses BuildJDK24 for
Java 25+; create a distinct BuildJDK25 and update the Makefile logic so when
JAVA_RELEASE_NUMBER >= 25 it sets BUILDJDKTool = BuildJDK25 (instead of
BuildJDK24). Add a new BuildJDK25 class mirroring BuildJDK24's pattern (ensuring
it generates classfile version 69 when appropriate, similar to
BcelUtil.javaVersion handling), and adjust the Makefile block that checks
JAVA_RELEASE_NUMBER to set JAVA25 := 1 and set BuildJDKTool = BuildJDK25; keep
the existing JAVA25_HOME fallback to JAVA_HOME unchanged. Ensure references to
BuildJDK24 remain for Java 24, and update any comments to remove the stale
"Temporary" note.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@java/Makefile`:
- Around line 51-60: Makefile currently reuses BuildJDK24 for Java 25+; create a
distinct BuildJDK25 and update the Makefile logic so when JAVA_RELEASE_NUMBER >=
25 it sets BUILDJDKTool = BuildJDK25 (instead of BuildJDK24). Add a new
BuildJDK25 class mirroring BuildJDK24's pattern (ensuring it generates classfile
version 69 when appropriate, similar to BcelUtil.javaVersion handling), and
adjust the Makefile block that checks JAVA_RELEASE_NUMBER to set JAVA25 := 1 and
set BuildJDKTool = BuildJDK25; keep the existing JAVA25_HOME fallback to
JAVA_HOME unchanged. Ensure references to BuildJDK24 remain for Java 24, and
update any comments to remove the stale "Temporary" note.

---

Duplicate comments:
In `@java/Makefile`:
- Around line 2068-2081: No changes required: the Makefile's diff24 target and
its declaration (.PHONY: diff24 and target diff24) are correct as-is; leave the
four diff commands (prefixed with '-') and the explanatory comment about
excluded files (StackMapUtils24.java, ClassGen24.java, MethodGen24.java,
OperandStack24.java) untouched.
- Around line 24-25: Add a brief documentation comment above the Makefile
variable BuildJDKTool explaining that it selects which build target to use based
on JAVA_RELEASE_NUMBER (e.g., choose "BuildJDK" for older releases and
"BuildJDK24" for Java 24), and note the expected values of JAVA_RELEASE_NUMBER
and the two possible choices so maintainers understand the variable's purpose
and usage.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
java/daikon/chicory/Instrument.java (1)

211-224: ⚠️ Potential issue | 🟠 Major

Keep default boot-class exclusions when Chicory.boot_classes is configured.

Chicory.boot_classes is documented as “extra classes,” but the else if chain makes it replace the default loader == null, parent-loader, and reflect-package exclusions. If a user sets this regex, unmatched bootstrap/system classes can be instrumented and then fail because they cannot access daikon.chicory.Runtime.

Proposed fix
-    if (Chicory.boot_classes != null) {
+    if (Chicory.boot_classes != null) {
       Matcher matcher = Chicory.boot_classes.matcher(className);
       if (matcher.find()) {
         debug_transform.log("Ignoring boot class %s, matches boot_classes regex%n", className);
         return true;
       }
-    } else if (loader == null) {
+    }
+    if (loader == null) {
       debug_transform.log("Ignoring system class %s, class loader == null%n", className);
       return true;
     } else if (loader.getParent() == null) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@java/daikon/chicory/Instrument.java` around lines 211 - 224, The current
else-if chain causes Chicory.boot_classes to override default boot/system
exclusions; change the control flow so the default checks always run and the
user-specified regex is an additional independent exclusion. Concretely, make
the checks for loader == null (system class), loader.getParent() == null, and
className.startsWith("sun.reflect.") unconditional (independent ifs) and then,
if Chicory.boot_classes != null, run Matcher matcher =
Chicory.boot_classes.matcher(className) and skip only when matcher.find();
update the debug_transform.log calls to remain the same but remove the else
chaining that ties these conditions together.
java/daikon/chicory/Instrument24.java (2)

547-656: ⚠️ Potential issue | 🔴 Critical

Do not emit a partially built class after method instrumentation fails.

Unlike the BCEL path, this class is rebuilt from scratch. If an exception occurs mid-loop, the catch block logs and continues, leaving all remaining methods uncopied from classBuilder; transform can then return a class missing methods. Re-throw so the outer transform catch returns the original bytecode instead.

Proposed fix
     } catch (Exception e) {
       System.err.printf("Unexpected exception encountered: %s", e);
       e.printStackTrace();
+      throw new RuntimeException("Failed to instrument " + classInfo.class_name, e);
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@java/daikon/chicory/Instrument24.java` around lines 547 - 656, The catch
block around the method loop currently swallows exceptions and lets transform
return a partially built class; instead, after logging include a rethrow so the
outer transform can fall back to the original bytecode. Update the try/catch in
Instrument24 (the block iterating methods and calling
create_method_info_if_instrumented, copyMethodToOutputUnchanged,
instrumentMethod and classBuilder.withMethod) to rethrow the caught Exception
(or wrap it in a RuntimeException) after printing/logging, so the failure aborts
class rebuilding rather than emitting a partially built class.

208-224: ⚠️ Potential issue | 🟠 Major

Keep default boot-class exclusions when Chicory.boot_classes is configured.

Same issue as in Instrument.java: the user regex is treated as a replacement for default boot/system detection. With Chicory.boot_classes set, unmatched null-loader or platform-reflection classes can be instrumented even though they cannot access the Chicory runtime.

Proposed fix
-    if (Chicory.boot_classes != null) {
+    if (Chicory.boot_classes != null) {
       Matcher matcher = Chicory.boot_classes.matcher(className);
       if (matcher.find()) {
         debug_transform.log("Ignoring boot class %s, matches boot_classes regex%n", className);
         return true;
       }
-    } else if (loader == null) {
+    }
+    if (loader == null) {
       debug_transform.log("Ignoring system class %s, class loader == null%n", className);
       return true;
     } else if (loader.getParent() == null) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@java/daikon/chicory/Instrument24.java` around lines 208 - 224, The current
logic in Instrument24.java treats Chicory.boot_classes as a replacement for the
default boot/system exclusions (the if/else chain starting with "if
(Chicory.boot_classes != null) {...} else if (loader == null) {...}"), causing
unmatched null-loader or platform-reflection classes to be instrumented; change
the flow so the user regex in Chicory.boot_classes only adds extra exclusions
instead of replacing defaults: first, if Chicory.boot_classes != null, test
Matcher matcher = Chicory.boot_classes.matcher(className) and return true when
matcher.find(); then DO NOT use else-if — continue running the original default
checks (loader == null, loader.getParent() == null,
className.startsWith("sun.reflect."),
className.startsWith("jdk.internal.reflect."), etc.) as independent ifs so
default boot/system exclusions always apply in addition to the user-provided
regex.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@java/daikon/chicory/Instrument24.java`:
- Around line 888-912: The catch block that surrounds the insertion logic for
CodeElement inst currently swallows exceptions, allowing the transform to
proceed without inserting newCode (nonce initialization) while later code such
as callEnterOrExit still expects minfo.nonceLocal and the entry label mapping
(minfo.entryLabel/minfo.labelMap), which can produce invalid bytecode; change
the catch to log the exception and then fail the transform by rethrowing (e.g.,
wrap and throw a RuntimeException or a specific TransformException) so the
transformation aborts instead of continuing with inconsistent state. Ensure the
rethrow includes the original exception so stack traces are preserved and
reference the insertion context (instructions listIterator, inst, newCode,
minfo.entryLabel, and minfo.labelMap) in the log message.

---

Outside diff comments:
In `@java/daikon/chicory/Instrument.java`:
- Around line 211-224: The current else-if chain causes Chicory.boot_classes to
override default boot/system exclusions; change the control flow so the default
checks always run and the user-specified regex is an additional independent
exclusion. Concretely, make the checks for loader == null (system class),
loader.getParent() == null, and className.startsWith("sun.reflect.")
unconditional (independent ifs) and then, if Chicory.boot_classes != null, run
Matcher matcher = Chicory.boot_classes.matcher(className) and skip only when
matcher.find(); update the debug_transform.log calls to remain the same but
remove the else chaining that ties these conditions together.

In `@java/daikon/chicory/Instrument24.java`:
- Around line 547-656: The catch block around the method loop currently swallows
exceptions and lets transform return a partially built class; instead, after
logging include a rethrow so the outer transform can fall back to the original
bytecode. Update the try/catch in Instrument24 (the block iterating methods and
calling create_method_info_if_instrumented, copyMethodToOutputUnchanged,
instrumentMethod and classBuilder.withMethod) to rethrow the caught Exception
(or wrap it in a RuntimeException) after printing/logging, so the failure aborts
class rebuilding rather than emitting a partially built class.
- Around line 208-224: The current logic in Instrument24.java treats
Chicory.boot_classes as a replacement for the default boot/system exclusions
(the if/else chain starting with "if (Chicory.boot_classes != null) {...} else
if (loader == null) {...}"), causing unmatched null-loader or
platform-reflection classes to be instrumented; change the flow so the user
regex in Chicory.boot_classes only adds extra exclusions instead of replacing
defaults: first, if Chicory.boot_classes != null, test Matcher matcher =
Chicory.boot_classes.matcher(className) and return true when matcher.find();
then DO NOT use else-if — continue running the original default checks (loader
== null, loader.getParent() == null, className.startsWith("sun.reflect."),
className.startsWith("jdk.internal.reflect."), etc.) as independent ifs so
default boot/system exclusions always apply in addition to the user-provided
regex.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 22bb4871-8b1f-4e43-bf87-806566e84c49

📥 Commits

Reviewing files that changed from the base of the PR and between 102ec38 and 5313722.

📒 Files selected for processing (11)
  • Makefile
  • java/Makefile
  • java/daikon/chicory/Instrument.java
  • java/daikon/chicory/Instrument24.java
  • java/daikon/config/ParameterDoclet.java11
  • java/daikon/dcomp/BuildJDK.java
  • java/daikon/dcomp/Premain.java
  • java/daikon/suppress/NIS.java
  • java/daikon/test/split/SplitterFactoryTestUpdater.java
  • java/lib/README
  • java/lib/build.gradle

Comment on lines +888 to +912
CodeElement inst = null;
try {
ListIterator<CodeElement> li = instructions.listIterator();
while (li.hasNext()) {
inst = li.next();
if ((inst instanceof LineNumber) || (inst instanceof Instruction)) {
break;
}
}

// Label for new location of start of original code.
debugInstrument.log("entryLabel: %s%n", minfo.entryLabel);
assert inst != null : "@AssumeAssertion(nullness): inst will always be set in loop above";
minfo.labelMap.put(inst, minfo.entryLabel);

// Insert code before this LineNumber or Instruction.
// Back up iterator to point to `inst`.
li.previous();
for (CodeElement ce : newCode) {
li.add(ce);
}
} catch (Exception e) {
System.err.printf("Exception encountered: %s", e);
e.printStackTrace();
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Do not swallow entry-instrumentation insertion failures.

If this catch fires, the method can continue to exit instrumentation without the inserted nonce initialization, while callEnterOrExit still loads minfo.nonceLocal. That can generate invalid bytecode or mismatched enter/exit events; fail the transform instead.

Proposed fix
     } catch (Exception e) {
       System.err.printf("Exception encountered: %s", e);
       e.printStackTrace();
+      throw new RuntimeException("Failed to insert method-entry instrumentation for " + mgen, e);
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@java/daikon/chicory/Instrument24.java` around lines 888 - 912, The catch
block that surrounds the insertion logic for CodeElement inst currently swallows
exceptions, allowing the transform to proceed without inserting newCode (nonce
initialization) while later code such as callEnterOrExit still expects
minfo.nonceLocal and the entry label mapping (minfo.entryLabel/minfo.labelMap),
which can produce invalid bytecode; change the catch to log the exception and
then fail the transform by rethrowing (e.g., wrap and throw a RuntimeException
or a specific TransformException) so the transformation aborts instead of
continuing with inconsistent state. Ensure the rethrow includes the original
exception so stack traces are preserved and reference the insertion context
(instructions listIterator, inst, newCode, minfo.entryLabel, and minfo.labelMap)
in the log message.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (5)
java/daikon/dcomp/DCInstrument.java (2)

1341-1344: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Incorrect method skipping on exception.

If an exception occurs during the MethodGen constructor or earlier in the try block (e.g., line 1230), the local mgen variable is out of scope and the field this.mgen will still point to the MethodGen from the previous loop iteration. Calling skip_method(mgen) will then incorrectly record the previous (already successfully processed) method as skipped, while the actual failed method goes unrecorded.

Since you already have classname and m.getName() available in this catch block, you can record the skipped method directly and avoid relying on the mgen field completely.

🐛 Proposed fix
-        // TODO: Is it guaranteed that mgen is non-null by the time control reaches here?
-        if (mgen != null) {
-          skip_method(mgen);
-        }
+        skipped_methods.add(classname + "." + m.getName());
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@java/daikon/dcomp/DCInstrument.java` around lines 1341 - 1344, Update the
exception-handling skip path in DCInstrument to record the failed method
directly using the available classname and m.getName() values, rather than
checking or passing the stale this.mgen field to skip_method. Preserve the
existing behavior of recording the method as skipped when processing fails.

488-489: 🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

Concurrency hazard on static collections during class transformation.

Several static collections are mutated during class instrumentation without synchronization. Since the agent can transform classes concurrently (as indicated by the use of ConcurrentHashMap for javaClasses), this shared mutable state causes data races, which can lead to collection corruption, incorrect instrumentation, or infinite loops (e.g. in HashMap).

  • java/daikon/dcomp/DCInstrument.java#L488-L489: initialize junitTestClasses with a thread-safe set (e.g., ConcurrentHashMap.newKeySet()).
  • java/daikon/dcomp/DCInstrument.java#L517-L517: initialize static_field_id with a thread-safe map (e.g., Collections.synchronizedMap(new LinkedHashMap<>()) to preserve insertion order).
  • java/daikon/dcomp/DCInstrument.java#L524-L524: initialize accessFlags with a ConcurrentHashMap.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@java/daikon/dcomp/DCInstrument.java` around lines 488 - 489, Update the
static collection initializations in DCInstrument: make junitTestClasses a
concurrent set, make static_field_id a synchronized map backed by LinkedHashMap
to preserve insertion order, and make accessFlags a ConcurrentHashMap. Apply the
changes at java/daikon/dcomp/DCInstrument.java lines 488-489, 517-517, and
524-524.
java/daikon/chicory/Instrument24.java (1)

1492-1509: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Fix foundLine logic to correctly track line numbers across instructions.

In both Instrument.java and Instrument24.java, the boolean foundLine = false; declaration is inside the instruction loop. Consequently, it only reflects whether the current iteration evaluated a line number.

  • In Instrument24.java, a ReturnInstruction is not a LineNumber element, so foundLine is always false at the return, making !foundLine unconditionally true and breaking the check entirely.
  • In Instrument.java, it only checks if the return instruction has a LineNumberGen target, failing to account for line numbers attached to immediately preceding instructions.

To implement the intended logic ("Only do incremental lines if we haven't seen a line number since the last return"), move the declaration outside the loop.

  • java/daikon/chicory/Instrument24.java#L1492-L1509: Move boolean foundLine = false; to be declared before the for (CodeElement inst : il) loop, and reset it to false inside the if (inst instanceof ReturnInstruction) block after it is evaluated.
  • java/daikon/chicory/Instrument.java#L1276-L1305: Move boolean foundLine = false; to be declared before the for (InstructionHandle ih : il) loop, and reset it to false inside the case Const.ARETURN: block after it is evaluated.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@java/daikon/chicory/Instrument24.java` around lines 1492 - 1509, Move
foundLine outside the instruction loop in Instrument24.java (lines 1492-1509)
and reset it after processing each ReturnInstruction; retain the existing
line-number evaluation before the return check. Apply the same change in
Instrument.java (lines 1276-1305): declare foundLine before the
InstructionHandle loop and reset it after handling Const.ARETURN, so it tracks
line numbers since the previous return in both sites.
java/Makefile (1)

763-763: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Declare non-file targets as .PHONY.

These targets do not produce files named after themselves and should be explicitly declared .PHONY to avoid conflicts and silence static analysis warnings.

  • java/Makefile#L763-L763: explicitly declare tags-nojtb as .PHONY.
  • java/Makefile#L1288-L1288: explicitly declare api-test-each as .PHONY.
  • java/Makefile#L1302-L1302: explicitly declare api-private as .PHONY.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@java/Makefile` at line 763, Declare the non-file Make targets as phony: add
tags-nojtb, api-test-each, and api-private to the .PHONY declarations in
java/Makefile at lines 763-763, 1288-1288, and 1302-1302 respectively.

Source: Linters/SAST tools

Makefile (1)

381-381: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Exclude the Java 24 instrumentation classes from the version check. test-staged-dist scans every .class under ${DISTTESTDIRJAVA}, so Instrument24.class and other Java 24 outputs will fail classfile_check_version 52. Carve those files out or allow version 68 for them.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Makefile` at line 381, Update the test-staged-dist Java class scan around
classfile_check_version so Java 24 instrumentation outputs, including
Instrument24.class, are excluded from the version-52 check or validated with the
Java 24 classfile version 68. Keep the version-52 validation for all other
compiled classes.
♻️ Duplicate comments (1)
java/daikon/chicory/Instrument24.java (1)

907-910: 🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

Do not swallow internal instrumentation exceptions.

Across both files, internal helper methods catch and swallow Exceptions during bytecode manipulation instead of propagating them. If an exception is swallowed mid-instrumentation, the helper returns normally, and the top-level transform method will return a corrupted, partially instrumented class to the JVM, leading to a ClassFormatError or runtime crash.

  • java/daikon/chicory/Instrument24.java#L907-L910: Remove this try-catch block or wrap and re-throw as a RuntimeException.
  • java/daikon/chicory/Instrument24.java#L477-L480: Remove this try-catch block or wrap and re-throw as a RuntimeException.
  • java/daikon/chicory/Instrument24.java#L651-L654: Remove this try-catch block or wrap and re-throw as a RuntimeException.
  • java/daikon/chicory/Instrument.java#L443-L446: Remove this try-catch block or wrap and re-throw as a RuntimeException.
  • java/daikon/chicory/Instrument.java#L726-L729: Remove this try-catch block or wrap and re-throw as a RuntimeException.

Propagating these exceptions ensures that the top-level transform method's catch (Throwable t) block handles the failure and safely returns null (leaving the class cleanly uninstrumented).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@java/daikon/chicory/Instrument24.java` around lines 907 - 910, Stop
swallowing instrumentation exceptions in the helper catch blocks at
java/daikon/chicory/Instrument24.java lines 907-910, 477-480, and 651-654, and
java/daikon/chicory/Instrument.java lines 443-446 and 726-729: remove each catch
or rethrow the exception as a RuntimeException. Preserve propagation to the
top-level transform methods so their existing catch (Throwable t) handling
returns null for failed instrumentation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@java/daikon/chicory/Instrument24.java`:
- Around line 1492-1509: Move foundLine outside the instruction loop in
Instrument24.java (lines 1492-1509) and reset it after processing each
ReturnInstruction; retain the existing line-number evaluation before the return
check. Apply the same change in Instrument.java (lines 1276-1305): declare
foundLine before the InstructionHandle loop and reset it after handling
Const.ARETURN, so it tracks line numbers since the previous return in both
sites.

In `@java/daikon/dcomp/DCInstrument.java`:
- Around line 1341-1344: Update the exception-handling skip path in DCInstrument
to record the failed method directly using the available classname and
m.getName() values, rather than checking or passing the stale this.mgen field to
skip_method. Preserve the existing behavior of recording the method as skipped
when processing fails.
- Around line 488-489: Update the static collection initializations in
DCInstrument: make junitTestClasses a concurrent set, make static_field_id a
synchronized map backed by LinkedHashMap to preserve insertion order, and make
accessFlags a ConcurrentHashMap. Apply the changes at
java/daikon/dcomp/DCInstrument.java lines 488-489, 517-517, and 524-524.

In `@java/Makefile`:
- Line 763: Declare the non-file Make targets as phony: add tags-nojtb,
api-test-each, and api-private to the .PHONY declarations in java/Makefile at
lines 763-763, 1288-1288, and 1302-1302 respectively.

In `@Makefile`:
- Line 381: Update the test-staged-dist Java class scan around
classfile_check_version so Java 24 instrumentation outputs, including
Instrument24.class, are excluded from the version-52 check or validated with the
Java 24 classfile version 68. Keep the version-52 validation for all other
compiled classes.

---

Duplicate comments:
In `@java/daikon/chicory/Instrument24.java`:
- Around line 907-910: Stop swallowing instrumentation exceptions in the helper
catch blocks at java/daikon/chicory/Instrument24.java lines 907-910, 477-480,
and 651-654, and java/daikon/chicory/Instrument.java lines 443-446 and 726-729:
remove each catch or rethrow the exception as a RuntimeException. Preserve
propagation to the top-level transform methods so their existing catch
(Throwable t) handling returns null for failed instrumentation.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: e35a3b36-c20f-499f-9732-7e33cf93417a

📥 Commits

Reviewing files that changed from the base of the PR and between 5313722 and 46f1627.

📒 Files selected for processing (14)
  • Makefile
  • java/Makefile
  • java/daikon/DynComp.java
  • java/daikon/chicory/Instrument.java
  • java/daikon/chicory/Instrument24.java
  • java/daikon/chicory/MethodInfo.java
  • java/daikon/chicory/Runtime.java
  • java/daikon/config/ParameterDoclet.java11
  • java/daikon/config/ParameterDoclet.java8
  • java/daikon/dcomp/BuildJDK.java
  • java/daikon/dcomp/DCInstrument.java
  • java/daikon/dcomp/Premain.java
  • java/lib/README
  • java/lib/build.gradle

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (7)
java/daikon/dcomp/DCInstrument24.java (2)

1307-1321: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Do not emit a partially instrumented class after a method failure.

When quit_if_error is false, this handler records the failure and continues. The later class-element copy loop excludes every MethodModel. For a failed method, the instrumented overload can be absent or incomplete.

Other instrumented methods still decide at class scope that the target is instrumented and add DCompMarker. Calls can then fail with NoSuchMethodError. This also removes the only emitted version of special methods such as non-JDK <clinit> methods and JUnit methods.

Fall back to the complete original class, or record failed method signatures and make call-site dispatch use the uninstrumented signature.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@java/daikon/dcomp/DCInstrument24.java` around lines 1307 - 1321, Update the
method-failure handling around the catch block and later class-element copy loop
so a failed MethodModel never produces a partially instrumented class. When
quit_if_error is false, either abandon instrumentation and emit the complete
original class, or record failed method signatures and ensure call-site dispatch
uses their uninstrumented signatures; preserve special methods such as <clinit>
and JUnit methods, and only add DCompMarker when the resulting class is safely
instrumented.

1421-1433: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Keep non-blacklisted annotations.

In RuntimeVisibleAnnotationsAttribute, setting output to false for a single blacklisted annotation removes the whole copy path, and methodBuilder.with(me) only adds the original attribute unchanged. Build a filtered RuntimeVisibleAnnotationsAttribute.of(filteredAnnotations) list instead, and omit the attribute only when no entries remain.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@java/daikon/dcomp/DCInstrument24.java` around lines 1421 - 1433, Update the
RuntimeVisibleAnnotationsAttribute handling around rvaa.annotations() to collect
only annotations whose className is not in BLACKLISTED_ANNOTATIONS, logging each
excluded annotation. Add a filtered RuntimeVisibleAnnotationsAttribute.of result
to methodBuilder when the filtered list is nonempty, and omit the attribute when
all annotations are blacklisted instead of copying the original attribute
unchanged.
java/daikon/chicory/Instrument24.java (5)

1666-1700: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Handle top-level wildcard arguments individually.

The genericPart.equals("*") special case handles only a single wildcard. For the valid signature Ljava/util/Map<Ljava/lang/String;*>;, the loop stores the first argument and leaves * in current. Line 1695 then calls convertDescriptorToFqBinaryName("*"), which throws.

Handle * at depth zero as a ? token during the loop.

Proposed parser fix
       } else if (c == '>' ) {
         depth--;
         current.append(c);
+      } else if (c == '*' && depth == 0) {
+        params.add("?");
       } else if (c == ';' && depth == 0) {
         current.append(c);
         params.add(convertDescriptorToFqBinaryName(current.toString()));
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@java/daikon/chicory/Instrument24.java` around lines 1666 - 1700, Update
convertTypeArgumentsToBinaryNames to handle wildcard arguments while parsing:
when the loop encounters '*' at depth zero, add "?" as an individual parameter
and clear the current buffer instead of passing "*" to
convertDescriptorToFqBinaryName. Preserve existing nested-generic handling and
the standalone wildcard behavior.

353-367: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Publish runtime metadata only after successful class generation.

Both transformers publish MethodInfo and ClassInfo before bytecode generation completes. Returning null preserves the original class bytes but leaves metadata for a class that was not installed.

  • java/daikon/chicory/Instrument24.java#L353-L367: defer SharedData.methods, SharedData.new_classes, and SharedData.all_classes publication until classFile.build succeeds, or roll back all mutations on failure.
  • java/daikon/chicory/Instrument.java#L332-L346: apply the same transaction or rollback around instrumentClass and cg.getJavaClass().
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@java/daikon/chicory/Instrument24.java` around lines 353 - 367, Make runtime
metadata publication transactional in java/daikon/chicory/Instrument24.java at
lines 353-367: defer updates to SharedData.methods, SharedData.new_classes, and
SharedData.all_classes until classFile.build completes successfully, or roll
back every mutation when it fails. Apply the same transaction or rollback
behavior in java/daikon/chicory/Instrument.java at lines 332-346 around
instrumentClass and cg.getJavaClass(), ensuring failed transformations return
null without leaving MethodInfo or ClassInfo metadata published.

456-480: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Do not emit a partially transformed <clinit>.

Both addInitNotifyCalls implementations catch insertion failures and return a method that may be incomplete. The enclosing method-processing paths must propagate the failure instead of copying or replacing that method.

  • java/daikon/chicory/Instrument24.java#L456-L480: propagate the exception from addInitNotifyCalls and prevent Lines 651-654 from continuing with partial output.
  • java/daikon/chicory/Instrument.java#L414-L448: propagate the exception from addInitNotifyCalls and prevent Lines 726-729 from continuing with partial output.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@java/daikon/chicory/Instrument24.java` around lines 456 - 480, Update
addInitNotifyCalls in java/daikon/chicory/Instrument24.java (lines 456-480) and
java/daikon/chicory/Instrument.java (lines 414-448) to propagate insertion
failures instead of catching and returning with a partially transformed method;
adjust each enclosing method-processing path so Lines 651-654 and 726-729
respectively stop processing and do not copy or replace the affected <clinit>
after failure.

1204-1215: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Retarget exception handlers at the original method entry.

retargetStartLabel updates ExceptionCatch.tryStart() but not ExceptionCatch.handler(). If a valid handler targets the original offset-zero label, it still points before the new entry sequence. An exception can then re-enter Runtime.enter or target the wrong code.

Retarget ExceptionCatch.handler() to minfo.entryLabel when it equals minfo.oldStartLabel.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@java/daikon/chicory/Instrument24.java` around lines 1204 - 1215, Update
retargetStartLabel so the ExceptionCatch branch also checks whether ec.handler()
equals minfo.oldStartLabel and rebuilds the exception catch with handler set to
minfo.entryLabel, while preserving the existing tryStart retargeting behavior
and other fields.

651-654: 🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

Propagate instrumentMethod failures and avoid emitting incomplete transformed classes.

A failure in the classBuilder.withMethod callback only stops the method loop. Later, instrumentClass skips remaining original MethodModels at switch (ce) { case MethodModel mm -> {} default -> classBuilder.with(ce); }, so methods after the failure are omitted. Do not set classInfo.shouldInclude = true for failed methods, and let transform roll back shared metadata before returning null.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@java/daikon/chicory/Instrument24.java` around lines 651 - 654, Update the
instrumentMethod failure path in the classBuilder.withMethod callback to
propagate the exception instead of continuing the method loop or marking
classInfo.shouldInclude true. Ensure instrumentClass does not silently skip
remaining MethodModel entries after a failure, and have transform roll back
shared metadata before returning null for the failed transformation.
♻️ Duplicate comments (1)
java/daikon/chicory/Instrument24.java (1)

886-910: 🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

Abort when entry instrumentation cannot be inserted.

generateIncrementNonce sets minfo.nonceLocal before this try. If insertion fails, the catch logs the error and returns without adding newCode. Exit instrumentation then loads that local. The method can contain an uninitialized local access or fail verification.

Rethrow the exception. Also ensure the enclosing catch at Lines 651-654 does not continue with partial class output. This repeats the unresolved failure path from the previous review.

Proposed failure propagation
     } catch (Exception e) {
       System.err.printf("Exception encountered: %s", e);
       e.printStackTrace();
+      throw new IllegalStateException(
+          "Failed to insert method-entry instrumentation for " + mgen, e);
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@java/daikon/chicory/Instrument24.java` around lines 886 - 910, In the
entry-instrumentation block around the CodeElement iterator, rethrow any
insertion exception instead of logging and continuing, so partial
instrumentation cannot proceed with an uninitialized minfo.nonceLocal. Update
the enclosing catch around the caller near generateIncrementNonce to propagate
the failure and stop producing partial class output rather than treating the
instrumentation as successful.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@java/daikon/chicory/Instrument24.java`:
- Around line 1666-1700: Update convertTypeArgumentsToBinaryNames to handle
wildcard arguments while parsing: when the loop encounters '*' at depth zero,
add "?" as an individual parameter and clear the current buffer instead of
passing "*" to convertDescriptorToFqBinaryName. Preserve existing nested-generic
handling and the standalone wildcard behavior.
- Around line 353-367: Make runtime metadata publication transactional in
java/daikon/chicory/Instrument24.java at lines 353-367: defer updates to
SharedData.methods, SharedData.new_classes, and SharedData.all_classes until
classFile.build completes successfully, or roll back every mutation when it
fails. Apply the same transaction or rollback behavior in
java/daikon/chicory/Instrument.java at lines 332-346 around instrumentClass and
cg.getJavaClass(), ensuring failed transformations return null without leaving
MethodInfo or ClassInfo metadata published.
- Around line 456-480: Update addInitNotifyCalls in
java/daikon/chicory/Instrument24.java (lines 456-480) and
java/daikon/chicory/Instrument.java (lines 414-448) to propagate insertion
failures instead of catching and returning with a partially transformed method;
adjust each enclosing method-processing path so Lines 651-654 and 726-729
respectively stop processing and do not copy or replace the affected <clinit>
after failure.
- Around line 1204-1215: Update retargetStartLabel so the ExceptionCatch branch
also checks whether ec.handler() equals minfo.oldStartLabel and rebuilds the
exception catch with handler set to minfo.entryLabel, while preserving the
existing tryStart retargeting behavior and other fields.
- Around line 651-654: Update the instrumentMethod failure path in the
classBuilder.withMethod callback to propagate the exception instead of
continuing the method loop or marking classInfo.shouldInclude true. Ensure
instrumentClass does not silently skip remaining MethodModel entries after a
failure, and have transform roll back shared metadata before returning null for
the failed transformation.

In `@java/daikon/dcomp/DCInstrument24.java`:
- Around line 1307-1321: Update the method-failure handling around the catch
block and later class-element copy loop so a failed MethodModel never produces a
partially instrumented class. When quit_if_error is false, either abandon
instrumentation and emit the complete original class, or record failed method
signatures and ensure call-site dispatch uses their uninstrumented signatures;
preserve special methods such as <clinit> and JUnit methods, and only add
DCompMarker when the resulting class is safely instrumented.
- Around line 1421-1433: Update the RuntimeVisibleAnnotationsAttribute handling
around rvaa.annotations() to collect only annotations whose className is not in
BLACKLISTED_ANNOTATIONS, logging each excluded annotation. Add a filtered
RuntimeVisibleAnnotationsAttribute.of result to methodBuilder when the filtered
list is nonempty, and omit the attribute when all annotations are blacklisted
instead of copying the original attribute unchanged.

---

Duplicate comments:
In `@java/daikon/chicory/Instrument24.java`:
- Around line 886-910: In the entry-instrumentation block around the CodeElement
iterator, rethrow any insertion exception instead of logging and continuing, so
partial instrumentation cannot proceed with an uninitialized minfo.nonceLocal.
Update the enclosing catch around the caller near generateIncrementNonce to
propagate the failure and stop producing partial class output rather than
treating the instrumentation as successful.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 09962ba4-62e2-4a3e-98c6-0e093178737f

📥 Commits

Reviewing files that changed from the base of the PR and between 46f1627 and 2943bcd.

📒 Files selected for processing (6)
  • Makefile
  • java/Makefile
  • java/daikon/chicory/Instrument.java
  • java/daikon/chicory/Instrument24.java
  • java/daikon/dcomp/BuildJDK.java
  • java/daikon/dcomp/DCInstrument24.java

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants