Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
Update decision log and project requirements documentation for Java R…
…untime Compiler
  • Loading branch information
peter-lawrey committed Nov 21, 2025
commit 21e40437ebb87ca25e1861cb118c25ee9d10d20e
110 changes: 109 additions & 1 deletion src/main/docs/decision-log.adoc
Original file line number Diff line number Diff line change
@@ -1,3 +1,24 @@
= Java Runtime Compiler Decision Log
Chronicle Software
:toc:
:sectnums:
:lang: en-GB
:source-highlighter: rouge

This log records architectural and process choices for the Java Runtime Compiler.
Each entry uses the Nine-Box tag set and links back to `project-requirements.adoc` where possible.

== Decision Index

* RC-FN-001 Allow hyphenated descriptor class names
* RC-TEST-002 Align coverage gate with achieved baseline
* RC-FN-002 Cached compiler API and custom class loaders
* RC-NF-P-006 Performance and metaspace budget for cached compilation
* RC-RISK-026 Debug artefact directory safety

== Decisions

[[RC-FN-001]]
=== [RC-FN-001] Allow hyphenated descriptor class names

* Date: 2025-10-28
Expand Down Expand Up @@ -34,4 +55,91 @@
** Documentation for requirement JRC-TEST-014 is updated to the same value.
* Notes/Links:
** Thresholds maintained in `pom.xml`.
** Updated requirement: `src/main/docs/project-requirements.adoc`.
** Updated requirement: `src/main/adoc/project-requirements.adoc` (JRC-TEST-014).

[[RC-FN-002]]
=== [RC-FN-002] Cached compiler API and custom class loaders

Date :: 2025-11-14
Context ::
* Callers need a simple way to compile Java source from a string and obtain a `Class` at runtime.
* The project requirements JRC-FN-001 to JRC-FN-004 call for a singleton cached compiler and support for custom `ClassLoader` instances.
* Creating a new compiler for every call would waste CPU time and increase memory pressure.
Decision ::
* Use `CompilerUtils.CACHED_COMPILER` as the default entry point for simple compile and load operations.
* Expose `CachedCompiler` as a reusable component that caches compiled classes per class loader and supports optional debug directories for `.java` and `.class` files.
Alternatives ::
* Always construct a new `CachedCompiler` instance for each compilation. ::
** Pros: Very explicit lifecycle; no shared state.
** Cons: Higher overhead per call and no reuse of compiled classes.
* Provide only low level `CachedCompiler` APIs and no static helper. ::
** Pros: Maximum flexibility for advanced users.
** Cons: Common call sites would need boilerplate and could easily misuse the cache.
Rationale ::
* A shared cached compiler keeps the public API small and satisfies JRC-FN-002 while allowing advanced users to manage their own instances.
* Per class loader caching aligns with application isolation and typical container deployments.
Impact ::
* Most applications rely on the shared `CACHED_COMPILER`; misuse can pin classes for the lifetime of the class loader, so long running systems should treat loader choice carefully.
* Tests must exercise both the shared singleton and user supplied `CachedCompiler` instances, including custom `ClassLoader` paths.
Links ::
* `src/main/java/net/openhft/compiler/CompilerUtils.java`
* `src/main/java/net/openhft/compiler/CachedCompiler.java`
* `src/main/adoc/project-requirements.adoc` (JRC-FN-001 to JRC-FN-005)

[[RC-NF-P-006]]
=== [RC-NF-P-006] Performance and metaspace budget for cached compilation

Date :: 2025-11-14
Context ::
* Requirements JRC-NF-P-006 to JRC-NF-P-008 set limits on compilation latency, steady state invocation overhead, and metaspace growth.
* Initialising `JavaCompiler` and `StandardJavaFileManager` is relatively expensive and must not be repeated unnecessarily.
* Debug output is helpful but can slow down compilation and increase disk activity.
Decision ::
* Reuse a single `JavaCompiler` and `StandardJavaFileManager` across compilation calls via `CompilerUtils.reset()`.
* Maintain a `MyJavaFileManager` per class loader inside `CachedCompiler` to isolate compiled artefacts while still sharing core compiler infrastructure.
* Use a small default option set (`-g`, `-nowarn`) and allow callers to supply additional options when constructing a `CachedCompiler`.
Alternatives ::
* Instantiate a new `JavaCompiler` and file manager for every compilation. ::
** Pros: Simple to reason about; no shared mutable state.
** Cons: Slower start up and higher CPU cost for repeated compiles.
* Disable debug information and warnings by default. ::
** Pros: Slightly faster and smaller class files.
** Cons: Harder to debug issues and reconcile compiler output with source.
Rationale ::
* Reusing compiler infrastructure is the most effective way to keep compile times within the required budget while still supporting rich diagnostics.
* Per class loader file managers help bound metaspace growth and keep compiled classes associated with the correct loader.
Impact ::
* First use of the compiler pays the initialisation cost; subsequent compiles should be significantly faster.
* Long running processes that create many class loaders must still monitor metaspace usage; tests and benchmarks track these behaviours.
Links ::
* `src/main/java/net/openhft/compiler/CompilerUtils.java`
* `src/main/java/net/openhft/compiler/CachedCompiler.java`
* `src/main/adoc/project-requirements.adoc` (JRC-NF-P-006 to JRC-NF-P-008)

[[RC-RISK-026]]
=== [RC-RISK-026] Debug artefact directory safety

Date :: 2025-11-14
Context ::
* Requirement JRC-FN-005 mandates a debug mode that writes `.java` and `.class` files to user supplied directories.
* Requirement JRC-RISK-026 requires a retention policy and safe handling of those directories.
* Without validation a hostile caller could attempt directory traversal using relative paths.
Decision ::
* Treat the configured source and class directories as roots and resolve all debug file paths beneath them using the `safeResolve` helper.
* Reject any path that would escape the configured root directory and throw an `IllegalArgumentException` when traversal is detected.
Alternatives ::
* Write files using the relative paths as supplied without extra checks. ::
** Pros: Simpler implementation.
** Cons: Risk of writing outside the intended directory tree.
* Remove debug file emission from the library. ::
** Pros: Eliminates this class of risk.
** Cons: Makes troubleshooting much harder and violates JRC-FN-005.
Rationale ::
* Safe resolution of paths balances the need for useful debug output with the requirement to keep file writes constrained to explicit directories.
* Failing fast on invalid paths helps surface configuration issues early in development and testing.
Impact ::
* Callers must choose appropriate root directories; attempts to write using paths that escape those roots will fail.
* Future work on retention tooling should build on the same root directory assumptions.
Links ::
* `src/main/java/net/openhft/compiler/CachedCompiler.java` (`safeResolve`)
* `src/main/adoc/project-requirements.adoc` (JRC-FN-005, JRC-RISK-026)
Original file line number Diff line number Diff line change
@@ -1,29 +1,36 @@
= Java Runtime Compiler Project Requirements
:toc:
:lang: en-GB
:source-highlighter: rouge
:sectnums:

== Requirement Catalogue

This document captures all `JRC-*` requirements for the Java Runtime Compiler library using a Nine-Box style tag set grouped by functional, non-functional and testing concerns.
Each identifier links code, decision records and operational guidance back to the same requirement row.

=== Functional (FN)

JRC-FN-001 :: The library *MUST* compile Java source provided as a `String` and return a `Class<?>` at runtime.
JRC-FN-002 :: The public API *MUST* expose a singleton _cached compiler_ capable of avoiding redundant compilations.
JRC-FN-003 :: The library *MUST* support the compilation of nested classes contained in the same source unit.
JRC-FN-004 :: Callers *MUST* be able to supply a custom `ClassLoader`; default is the current context loader.
JRC-FN-005 :: A _debug mode_ *MUST* emit `.java` and `.class` artefacts to configurable directories for IDE inspection.
* _Decision:_ link:../docs/decision-log.adoc#RC-FN-002[RC-FN-002] (cached compiler API) and link:../docs/decision-log.adoc#RC-RISK-026[RC-RISK-026] (debug artefact safety).

=== Non-Functional Performance (NF-P)
=== Non-Functional - Performance (NF-P)

JRC-NF-P-006 :: First-time compilation of a <1 kLoC class *SHOULD* complete in 500 ms on a 3 GHz x86-64 CPU.
JRC-NF-P-006 :: First-time compilation of a <1 kLoC class *SHOULD* complete in <= 500 ms on a 3 GHz x86-64 CPU.
JRC-NF-P-007 :: Steady-state invocation latency of compiled methods *MUST* be within 10 % of statically compiled code.
JRC-NF-P-008 :: Peak metaspace growth per 1 000 unique dynamic classes *MUST NOT* exceed 50 MB.
* _Decision:_ link:../docs/decision-log.adoc#RC-NF-P-006[RC-NF-P-006] (performance and metaspace budget).

=== Non-Functional Security (NF-S)
=== Non-Functional - Security (NF-S)

JRC-NF-S-009 :: The API *MUST* allow callers to plug in a source-code validator to reject untrusted or malicious input.
JRC-NF-S-010 :: Compilation *MUST* occur with the permissions of the hosting JVM; the library supplies _no_ elevated privileges.

=== Non-Functional Operability (NF-O)
=== Non-Functional - Operability (NF-O)

JRC-NF-O-011 :: All internal logging *SHALL* use SLF4J at `INFO` or lower; compilation errors log at `ERROR`.
JRC-NF-O-012 :: A health-check helper *SHOULD* verify JDK compiler availability and JVM module flags at start-up.
Expand All @@ -32,7 +39,8 @@ JRC-NF-O-013 :: The library *MUST* expose a counter metric for successful and fa
=== Test / QA (TEST)

JRC-TEST-014 :: Unit tests *MUST* cover >= 90 % of public API branches, including happy-path and diagnostics.
JRC-TEST-015 :: Concurrency tests *MUST* exercise ≥ 64 parallel compile requests without race or deadlock.
* _Decision:_ link:../docs/decision-log.adoc#RC-TEST-002[RC-TEST-002] (coverage gate alignment).
JRC-TEST-015 :: Concurrency tests *MUST* exercise >= 64 parallel compile requests without race or deadlock.
JRC-TEST-016 :: A benchmark suite *SHOULD* publish compile latency and runtime call performance on CI.

=== Documentation (DOC)
Expand Down