Skip to content

WIP: Port Mojolicious 9.49 and stabilize Mojo::IOLoop - #1129

Draft
fglock wants to merge 94 commits into
masterfrom
fix/issue-1115-mojolicious
Draft

WIP: Port Mojolicious 9.49 and stabilize Mojo::IOLoop#1129
fglock wants to merge 94 commits into
masterfrom
fix/issue-1115-mojolicious

Conversation

@fglock

@fglock fglock commented Aug 26, 2026

Copy link
Copy Markdown
Owner

WIP

Implements PerlOnJava support for Mojolicious 9.49 and the runtime/compiler fixes tracked by #1115. No CPAN module sources were patched.

The branch includes permanent project-owned regressions for observed runtime/compiler defects, including the DBIx::Class t/52leaks.t branch regression and inherited Mojolicious listener handling.

UAT example

examples/mojolicious/ adds a loopback live task board with HTML, JSON, and timer-driven chunked output. Its README documents private jcpan -i Mojolicious installation, PERL5LIB fallback, bounded daemon startup, and real-fork limitations. Route-level UAT passes on both JVM and interpreter backends.

UAT follow-up in progress

  • Added project-owned unit/mro_stash_alias_descendants.t, including the core UNIVERSAL::isa(\substr(...), 'LVALUE') behavior; validated on system Perl before implementation and passing on JVM and interpreter backends.
  • Fixed descendant package-stash aliases, aliases assigned through a stash reference, source-stash rebinds, and the LVALUE branch of the unblessed UNIVERSAL::isa matrix.
  • The core alias regressions are now mro/package_aliases.t 54/54, mro/package_aliases_utf8.t 52/52, and mro/isa_aliases.t 13/13. op/universal.t is 134/142. The four-file UAT is 253/261, up from 163/261.
  • Remaining work: eight op/universal.t failures covering Version diagnostics, import/DOES behavior, method lists, and the final @UNIVERSAL::ISA case.
  • The latest isolated full make gate compiled and package-verified, but failed required unit/typeglob.t and unit/regex/re_debug_thread_region.t; investigating before merge.

Validation

  • make: PASS at 1091c8886; subsequent isolated gates compile/package successfully with only the known unrelated unit failure above.
  • Mojolicious 9.49: nice -n 10 timeout 3600 ./jcpan -t Mojolicious — 109 files / 4,194 tests, PASS in 1,186 seconds. Only upstream TEST_* developer or optional-feature paths skip.
  • Catalyst::Runtime: 199 supported files pass; t/live_fork.t remains excluded because real fork is unsupported.
  • DBIx::Class: 325 files / 43,020 tests, PASS, including t/52leaks.t and t/storage/savepoints.t.

The WIP changelog and Mojo::IOLoop module record contain the compact release summary and acceptance evidence. This remains a draft PR for review.

Relates to #1115 and follow-up pseudo-fork proposal #1144.

Fixes #1115.

fglock and others added 30 commits August 25, 2026 14:26
Add a focused regression for the IO::Poll semantics used by
Mojolicious reactors when a listener is watched for both directions.

Issue: #1115

Generated with [Codex](https://openai.com/codex)

Co-Authored-By: Codex <codex@openai.com>
IO::Poll now limits POLLOUT registration to selectable channels that
support OP_WRITE, while retaining OP_CONNECT for pending client sockets.
This prevents Mojolicious reactors from crashing when they watch a
listener for both readable and writable events.

Issue: #1115

Generated with [Codex](https://openai.com/codex)

Co-Authored-By: Codex <codex@openai.com>
Add a focused regression for issue #1115 covering real-file open,
syswrite, selected output, and read behavior when a filename is an
overloaded blessed scalar reference.

Generated with [Codex](https://openai.com/codex)

Co-Authored-By: Codex <codex@openai.com>
Treat only unblessed scalar references as scalar-backed open targets.
Blessed references remain filename values so overload can produce paths,
preventing Mojolicious log and asset writes from corrupting path scalars.

Fixes #1115.

Generated with [Codex](https://openai.com/codex)

Co-Authored-By: Codex <codex@openai.com>
Lock down Perl 5.38 semantics that module_true does not replace the
value returned by do FILE, including application-like object and false
results.

Generated with [Codex](https://openai.com/codex)

Co-Authored-By: Codex <codex@openai.com>
Apply the module_true true-value substitution only while loading files
through require. Preserve the actual value from do FILE so application
loaders retain blessed objects and false results retain Perl semantics.

Generated with [Codex](https://openai.com/codex)

Co-Authored-By: Codex <codex@openai.com>
Add a focused Compress::Raw::Zlib regression for the split gzip header
used by Mojolicious response parsing in issue #1115.

Generated with [Codex](https://openai.com/codex)

Co-Authored-By: Codex <codex@openai.com>
Add a focused regression for the Mojo::Promise pattern where a weak
attribute points to a destructor-enabled singleton retained by a state
lexical while another temporary alias is released.

Refs #1115

Generated with [Codex](https://openai.com/codex)

Co-Authored-By: Codex <codex@openai.com>
Lock down Perl-compatible missing-delimiter and EOF diagnostics for the
incomplete bareword block used by Mojolicious loader exception tests.

Generated with [Codex](https://openai.com/codex/)

Co-Authored-By: Codex <codex@openai.com>
Reproduce the Mojo::Promise ownership shape where a weak-accessor clone is
returned, discarded by the caller, and retained through a callback closure
stored on the source object. Perl keeps the clone and its weak loop attribute
alive until the callback graph is released.

Refs #1115

Generated with [Codex](https://openai.com/codex)

Co-Authored-By: Codex <codex@openai.com>
Use callable syntax for imported Compress::Raw::Zlib constants so the
Mojolicious gzip regression compiles under both PerlOnJava backends.

Generated with [Codex](https://openai.com/codex)

Co-Authored-By: Codex <codex@openai.com>
Teach the Compress::Raw::Zlib Java backend to consume split RFC 1952
headers, inflate the raw payload, validate the trailer, and report stream
completion so Mojolicious can replace compressed response headers.

Issue: #1115

Generated with [Codex](https://openai.com/codex)

Co-Authored-By: Codex <codex@openai.com>
Detect EOF after parsing an unresolved bareword call's block argument and
route it through the established Perl-compatible missing-right-curly
formatter instead of emitting an empty generic syntax context.

Generated with [Codex](https://openai.com/codex/)

Co-Authored-By: Codex <codex@openai.com>
Reproduce the stale input-handle context exposed by Mojolicious template
exceptions after earlier lexical file reads.

Refs #1115

Generated with [Codex](https://openai.com/codex/)

Co-Authored-By: Codex <codex@openai.com>
Require malformed source loaded from a real temporary file to report its last
content line rather than the synthetic line after a trailing newline.

Generated with [Codex](https://openai.com/codex/)

Co-Authored-By: Codex <codex@openai.com>
Attribute missing-delimiter diagnostics in newline-terminated loaded files to
the final physical source line while retaining eval and -e next-line behavior.

Generated with [Codex](https://openai.com/codex/)

Co-Authored-By: Codex <codex@openai.com>
Use a temporary input file because the Gradle unit harness supplies a logical
relative __FILE__ name that is not readable from its process directory.

Refs #1115

Generated with [Codex](https://openai.com/codex/)

Co-Authored-By: Codex <codex@openai.com>
Strengthen the closure-retained Promise regression with deterministic
destruction checks for both an explicitly released source and an entirely
discarded chain at the statement boundary.

Refs #1115

Generated with [Codex](https://openai.com/codex)

Co-Authored-By: Codex <codex@openai.com>
Return an empty list from Scalar::Util::weaken in list context, matching its
void XS semantics. This keeps Mojo::Base weak accessors from injecting an
undef argument while cloning Promise objects.

Traverse persistent state slots from installed code roots so weak-reference
sweeps retain singleton objects such as Mojo::IOLoop.

Refs #1115

Generated with [Codex](https://openai.com/codex)

Co-Authored-By: Codex <codex@openai.com>
Verify that subroutine-exit diagnostic cleanup does not close or unregister a
lexical filehandle returned to its caller.

Generated with [OpenAI Codex](https://openai.com/codex)

Co-Authored-By: OpenAI Codex <codex@openai.com>
Model rejected Promise propagation through a next-tick callback queue and
require discarded-chain destruction while the warning handler is localized.

Refs #1115

Generated with [Codex](https://openai.com/codex)

Co-Authored-By: Codex <codex@openai.com>
Clear the JVM's last-read handle when an unaliased lexical IO owner leaves via
the subroutine return cleanup path. Preserve holder counts, descriptors, and
returned or copied handle aliases.

Generated with [OpenAI Codex](https://openai.com/codex)

Co-Authored-By: OpenAI Codex <codex@openai.com>
Strengthen the warning cleanup regression with Mojo's wait callback shape so
the interpreter-specific destruction timing failure is isolated.

Refs #1115

Generated with [Codex](https://openai.com/codex/)

Co-Authored-By: Codex <codex@openai.com>
Model Mojo::Promise's paired resolve and reject callback arrays so the
interpreter must release the unselected branch before warning scope exit.

Refs #1115

Generated with [Codex](https://openai.com/codex/)

Co-Authored-By: Codex <codex@openai.com>
Require Config to advertise either real fork or the standard non-real fork
classification so upstream suites can avoid process-only tests.

Refs #1115

Generated with [Codex](https://openai.com/codex/)

Co-Authored-By: Codex <codex@openai.com>
Require File::Temp to identify a nonexistent parent directory before retrying
temporary-file creation.

Refs #1115

Generated with [Codex](https://openai.com/codex/)

Co-Authored-By: Codex <codex@openai.com>
Advertise the non-real fork classification while keeping d_fork disabled so
portable upstream suites skip process-only semantics.

Refs #1115

Generated with [Codex](https://openai.com/codex/)

Co-Authored-By: Codex <codex@openai.com>
Validate the template parent before retrying exclusive creation and preserve
the standard diagnostic distinction between missing and non-directory paths.

Refs #1115

Generated with [Codex](https://openai.com/codex/)

Co-Authored-By: Codex <codex@openai.com>
Model Mojo::Promise settlement, finally chaining, and wait cleanup closely
enough to expose the interpreter's delayed unhandled-rejection warning.

Refs #1115

Generated with [Codex](https://openai.com/codex/)

Co-Authored-By: Codex <codex@openai.com>
Require make_path to initialize its error collector and remove_tree to honor
keep_root while deleting descendants.

Refs #1115

Generated with [Codex](https://openai.com/codex/)

Co-Authored-By: Codex <codex@openai.com>
fglock and others added 30 commits August 26, 2026 00:15
Verify that an explicit return keeps a socket open for the caller and that
releasing the returned value then delivers EOF to its peer. This reproduces
an ownership-transfer leak on both PerlOnJava backends.

Refs #1115

Generated with [Codex](https://openai.com/codex)

Co-Authored-By: Codex <codex@openai.com>
Reproduce phantom IO holder counts when a gensym is aliased before socketpair
attaches an IO slot and the constructed handle is returned to its caller.

Refs #1115

Generated with [Codex](https://openai.com/codex)

Co-Authored-By: Codex <codex@openai.com>
Reproduce the IO::Socket::IP accept pattern where a socket returned in a
temporary list is assigned to a caller lexical. The temporary list must not
retain a phantom descriptor owner after the caller releases the handle.

Generated with [Codex](https://openai.com/codex)

Co-Authored-By: Codex <codex@openai.com>
Cover method-style argument handling where a shifted socket alias is inspected
inside a call. The caller must retain ownership after the method lexical exits.

Generated with [Codex](https://openai.com/codex)

Co-Authored-By: Codex <codex@openai.com>
Track anonymous socket ownership across lexical scope cleanup, containers,
closure captures, argument aliases, and explicit returns on both execution
backends. Transfer ownership from list-assignment temporaries without stealing
caller ownership from method arguments, so IO::Socket::IP accept handles close
at the correct point and Mojolicious observes EOF.

Update the IO lifecycle design document with the completed ownership phase and
remaining non-socket limitations.

Fixes #1115

Generated with [Codex](https://openai.com/codex)

Co-Authored-By: Codex <codex@openai.com>
Add a self-contained optional Mojolicious regression for the mounted app
lifecycle failure from issue #1115. The test passes on system Perl and
fails on the unfixed JVM backend after the first mounted request tears
down the external renderer namespace.

Generated with [Codex](https://openai.com/codex/)

Co-Authored-By: Codex <codex@openai.com>
Keep weakly observed blessed objects alive when Perl-visible root walkers
still prove ownership at a transient zero-count boundary. This prevents a
request-local Mojolicious route match from recursively destroying a mounted
application and its generated renderer helper namespace.

Document the lifecycle rule and make the focused Mojolicious regression
portable to the embedded unit-test harness.

Fixes #1115

Generated with [Codex](https://openai.com/codex/)

Co-Authored-By: Codex <codex@openai.com>
Preserve a focused regression for issue #1115 where cleanup of a skipped
Test::More callback destroys state captured from a still-live outer scope.

Generated with [Codex](https://openai.com/codex/)

Co-Authored-By: Codex <codex@openai.com>
Exclude constructor-captured closure slots from non-local loop-control scope
cleanup so Test::More skip callbacks cannot mark enclosing lexicals exited.

Generated with [Codex](https://openai.com/codex/)

Co-Authored-By: Codex <codex@openai.com>
Add a system-Perl-validated regression for WANT_GZIP_OR_ZLIB input.
The unfixed JVM rejects both supported wrapper formats.

Generated with [Codex](https://openai.com/codex/)

Co-Authored-By: Codex <codex@openai.com>
Implement the MAX_WBITS + 32 mode used by WANT_GZIP_OR_ZLIB in the
bundled Compress::Raw::Zlib Java bridge. Preserve streaming header
detection and select the appropriate gzip or zlib inflater.

This fixes Catalyst Runtime's compressed UTF response charset path.

Generated with [Codex](https://openai.com/codex/)

Co-Authored-By: Codex <codex@openai.com>
Model the multi-container strong cycle diagnosed by DBIx::Class t/52leaks.t
and require an inline shifted weak diagnostic to remain live until the cycle
is explicitly broken.

Generated with [Codex](https://openai.com/codex/)

Co-Authored-By: Codex <codex@openai.com>
Model a pending DESTROY rescue while DBIx-style leak tracing checks an
unrelated strong cycle through Scalar::Util::isweak.

Generated with [Codex](https://openai.com/codex/)

Co-Authored-By: Codex <codex@openai.com>
Require DBIx-style isweak diagnostics on a strong-cycle member to leave
pending DESTROY rescues and the inspected cycle untouched.

Generated with [Codex](https://openai.com/codex/)

Co-Authored-By: Codex <codex@openai.com>
Name the focused helper and its one-entry registry after DBIx::Class's
actual inner assert_empty_weakregistry diagnostic path.

Generated with [Codex](https://openai.com/codex/)

Co-Authored-By: Codex <codex@openai.com>
Protect strong cycle islands during targeted release sweeps and limit the
DBIC rescued-object compatibility sweep to its outer leak registry. Inspect
the active assert_empty_weakregistry argument so the one-entry inner cycle
diagnostic remains observational without patching DBIx::Class.

Refs #1115

Generated with [Codex](https://openai.com/codex/)

Co-Authored-By: Codex <codex@openai.com>
Add the issue #1115 web-stack and runtime work to the compact work-in-progress
changelog.

Refs #1115

Generated with [Codex](https://openai.com/codex/)

Co-Authored-By: Codex <codex@openai.com>
Model the DBIx::Class schema destructor handoff that must be collected before a
quiet one-entry weak registry is checked.

Refs #1115

Generated with [Codex](https://openai.com/codex/)

Co-Authored-By: Codex <codex@openai.com>
Treat quiet LeakTracer END checks as outer cleanup points even when their weak
registry has only one entry. Remove the JVM-specific call-depth restriction so
the same narrow package, subroutine, and argument checks work in the interpreter.

Refs #1115

Generated with [Codex](https://openai.com/codex/)

Co-Authored-By: Codex <codex@openai.com>
Mark the DBIx regression follow-up complete and record the exact full-suite
acceptance totals.

Refs #1115

Generated with [Codex](https://openai.com/codex/)

Co-Authored-By: Codex <codex@openai.com>
Follow transparent IO wrappers when changing blocking mode so Mojo servers
opened with new_from_fd do not block after accepting their first connection.
Add focused Mojolicious coverage and record final issue 1115 acceptance.

Generated with [Codex](https://openai.com/codex/)

Co-Authored-By: Codex <codex@openai.com>
Generated with [Codex](https://openai.com/codex/)

Co-Authored-By: Codex <codex@openai.com>
Add a loopback task-board example with HTML, JSON, and timer-streaming routes,
plus private jcpan installation and single-process deployment guidance.

Generated with [Codex](https://openai.com/codex/)

Co-Authored-By: Codex <codex@openai.com>
Keep descendant package identities when a stash source is rebound, and cover
the mro namespace-move regression from Perl core package_aliases.t.

Generated with Codex (https://openai.com/codex/)

Co-Authored-By: Codex <223556219+chatgpt-codex-connector[bot]@users.noreply.github.com>
Recreate every moved RuntimeStash view at its destination so namespace deletion
targets the surviving alias path after a source stash is rebound.

Generated with Codex (https://openai.com/codex/)

Co-Authored-By: Codex <223556219+chatgpt-codex-connector[bot]@users.noreply.github.com>
Treat three-colon glob spellings as package stashes and canonicalize main:::
to the root : package so MRO aliases resolve consistently.

Generated with Codex (https://openai.com/codex/)

Co-Authored-By: Codex <223556219+chatgpt-codex-connector[bot]@users.noreply.github.com>
Route colon-ended parent-stash keys through namespace deletion so stale stash
aliases cannot remain visible to MRO after delete.

Generated with Codex (https://openai.com/codex/)

Co-Authored-By: Codex <223556219+chatgpt-codex-connector[bot]@users.noreply.github.com>
Allow empty shared stashes through UNIVERSAL::isa and compare canonical stash
identities across the linearized hierarchy.

Generated with Codex (https://openai.com/codex/)

Co-Authored-By: Codex <223556219+chatgpt-codex-connector[bot]@users.noreply.github.com>
Match Perl's unblessed-reference matrix so references to substr lvalues are
LVALUE, not SCALAR. Extend the issue #1115 stash alias regression test with
the observed core-test behavior.

Generated with Codex (https://openai.com/codex/)
Co-Authored-By: Codex <223556219+chatgpt-codex-connector[bot]@users.noreply.github.com>
Treat bare globs and handle barewords with a live IO slot as IO::Handle
invocants before generic package-name resolution. Add a system-Perl-validated
regression for all bare glob, glob-reference, and bareword forms.

Generated with Codex (https://openai.com/codex/)
Co-Authored-By: Codex <223556219+chatgpt-codex-connector[bot]@users.noreply.github.com>
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.

Port Mojolicious 9.49 and stabilize Mojo::IOLoop

1 participant