Skip to content

[#91] Draft increment: Support JDKs with strong encapsulation - #184

Draft
peter-lawrey wants to merge 5 commits into
developfrom
feat/Java-Runtime-Compiler-91-opt-in-methodhandles-lookup-child
Draft

[#91] Draft increment: Support JDKs with strong encapsulation#184
peter-lawrey wants to merge 5 commits into
developfrom
feat/Java-Runtime-Compiler-91-opt-in-methodhandles-lookup-child

Conversation

@peter-lawrey

Copy link
Copy Markdown
Member

What this draft demonstrates

The remote issue is reopened. Local 7fe1f27 implements the public Lookup/anchor strategy and the full suite passed 48/0.

Why publish it now

This makes the local partial/design/research work for #91 reviewable without claiming that the broader issue is complete. Review can now decide whether to keep the increment, change direction, or stop the work.

Known gap

Publish as an increment; retain Java 8 and finish compiler-owned child-loader/arbitrary-package cases on JDK 17/21/25.

Review status

Draft partial — do not mark ready or close the issue until the known gap is resolved or explicitly split.

Validation

  • git diff --check against ea: passed.
  • Internal .pr/ scaffolding and local workspace paths: removed.
  • Existing focused/research evidence is described above; it was not rerun during this publication pass.
  • Remote CI, product/consumer decisions and maintainer review remain authoritative.

Tracking

Related to #91. This PR deliberately does not use a closing keyword.

peter-lawrey and others added 5 commits August 19, 2026 19:21
Local addressment for the 2022-backlog PR programme (see .pr/NOTES.md).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Runtime compilation already works on JDK 17/21 without
--add-opens because MyJavaFileManager bypasses setAccessible via the
Unsafe 'override' field offset. This hardens the fallback: when making the
delegate's internal listLocationsForModules/inferModuleName accessible throws
(e.g. InaccessibleObjectException on a future JDK that removes the Unsafe
path), the helper now returns a neutral default (empty module list / null)
instead of failing the whole compilation. Single-class compilation against the
application class path does not need module-location resolution, so the library
keeps working without encapsulation flags. The Java 8 path is unchanged.

invokeNamedMethodIfAvailable now takes the caller's default; the two tests that
reflect it are updated to the new signature, and the missing-method test now
asserts the default is returned rather than an exception thrown. Adds
compilesAndLoadsClassWithoutEncapsulationFlags as a guard that runtime compile
and load succeed with no --add-opens configured.

Verified on JDK 21 (full suite, 45 tests green); 17/25 not available here.

Refs #91

Co-Authored-By: Claude Opus 4.8 <noreply@noreply.anthropic.com>
First of the two class-definition strategies from issue #91. Adds a non-Unsafe
path that defines a compiled class in a caller-supplied MethodHandles.Lookup's
package and class loader via the public Lookup#defineClass(byte[]) (Java 9+):

  - CompilerUtils.defineClass(MethodHandles.Lookup, byte[]) -- no sun.misc.Unsafe,
    no setAccessible; the Lookup#defineClass method is resolved reflectively at
    class init so the Java 8 source root still compiles and runs (throws
    UnsupportedOperationException on 8, where the Unsafe path remains the fallback).
  - CompilerUtils.isAnchorDefineClassSupported() capability probe.
  - CachedCompiler.loadFromJava(MethodHandles.Lookup, String, String) opt-in
    end-to-end overload.

The JDK enforces the anchor contract (same run-time package, PACKAGE access): a
cross-package class is rejected with IllegalArgumentException rather than being
force-defined, the qualitative safety difference from the raw Unsafe path.

AnchorDefineClassTest proves the anchor path defines into the anchor's own loader,
runs the instance, and rejects a foreign package. Full suite 48 tests green on
JDK 21 (was 45). Fail-before is a compile failure: the API is new.

Remaining (issue #91): the second strategy (compiler-owned child loader for
arbitrary package names) and the MR-JAR split that drops the reflective lookup on
9+ while keeping the Java 8 root. Design note:
needs-info-research/Java-Runtime-Compiler-91/anchor-mode.md.

Refs #91

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The lookup overload reused retained compiler output, eagerly initialised generated classes, and still initialised legacy Unsafe helpers. It could also define a primary class before a same-source superclass.

Scope output to each compilation, cache and serialise definitions by loader and binary name, retry unresolved batch dependencies, preserve non-initialising lookup semantics, and load the legacy definer lazily.

This prevents duplicate definitions and ordering failures while providing a genuinely Unsafe-independent Java 9+ path. Refs #91.
@peter-lawrey
peter-lawrey changed the base branch from ea to develop August 22, 2026 11:12
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.

1 participant