fix: jcpan HTTP::Client::Parallel + op/state.t interpreter regression#593
Merged
fix: jcpan HTTP::Client::Parallel + op/state.t interpreter regression#593
Conversation
3 tasks
Two unrelated issues blocked HTTP::Client::Parallel: 1. POSIX.pm did not export the termios constants nor the _SC_* sysconf() name constants used by POE::Wheel::Run (loaded transitively from HTTP::Client::Parallel via POE). The Java side already implemented _const_ECHO, _const_TCSANOW, etc., and POSIX.pm wired them into POSIX::ECHO, POSIX::TCSANOW, ... but they were missing from @EXPORT_OK so `use POSIX qw(ECHO ...)` died with "ECHO is not exported by the POSIX module". Add the termios and _SC_* names to @EXPORT_OK and provide a small sysconf() stub that returns sensible defaults (e.g. _SC_OPEN_MAX => 1024). 2. The 1-argument form `open FILEHANDLE` (used by Module::Install::DSL, which LWP::Online ships) crashed with "Modification of a read-only value" when the filehandle was given as a numeric literal such as `open 0`. The runtime tried to call set() on the readonly arg and was also picking the filename from $_ instead of from the global scalar of the same name as the filehandle. Rewrite the 1-arg open path to derive the filehandle name from the value (covering glob refs, bareword strings, and numeric literals like 0), look up the filename in $main::<name>, and only assign back to args[0] when it is a writable scalar. With both fixes, `jcpan -t HTTP::Client::Parallel` and its LWP::Online dependency build and pass their unit tests. Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
The interpreter backend (BytecodeCompiler) ignored `BlockNode.isLoop`,
so synthesized `last` operators inside bare blocks marked as a loop
target (e.g. the implicit break appended to `when` clauses, eval-block
loop control) escaped to the nearest real enclosing loop. The JVM
backend already does the right thing in EmitBlock — make the interpreter
match.
Symptom that triggered this: when state.t falls back to the interpreter
("Method too large, using interpreter backend"), the implicit `last`
emitted by `when (...)` to break out of the surrounding `given` block
was instead breaking out of the `foreach` containing the given. That
turned 4 passing "given" subtests into 1, taking op/state.t from
159/170 to 156/170.
Fix: in `BytecodeCompiler.visit(BlockNode)`, when `node.isLoop` is
true, push a `LoopInfo` (isTrueLoop=true, redo target = body start)
before compiling the statements, and patch the recorded break/next
jumps to the post-body PC and redo jumps to the body start before
popping. Locals are still restored because `last/next` jump to the
PC of `RESTORE_REGEX_STATE` / `POP_LOCAL_LEVEL`, which then run as
normal block teardown.
After this fix, op/state.t is back to 159/170 and the 4 "given"
subtests all pass cleanly.
Generated with [Devin](https://cli.devin.ai/docs)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
0c40001 to
4eba31f
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two related fixes (supersedes #592):
1.
jcpan -t HTTP::Client::Parallel(commit 15c0542)Two unrelated issues blocked the module:
POE::Wheel::Rundoesuse POSIX qw(sysconf setsid _SC_OPEN_MAX ECHO ICANON IEXTEN ISIG BRKINT ICRNL INPCK ISTRIP IXON CSIZE PARENB OPOST TCSANOW). The_const_*helpers andPOSIX::ECHOetc. were already defined, but the names were not in@EXPORT_OK, so the import died with"ECHO" is not exported by the POSIX module. Added the termios +_SC_*families to@EXPORT_OKand a smallsysconf()stub returning sensible defaults (e.g._SC_OPEN_MAX => 1024).open 0(1-arg open of a numeric literal).Module::Install::DSL(shipped byLWP::Online) doesopen 0 or die ...; $dsl = join "", <0>. PerlOnJava crashed withModification of a read-only value attempted at ./inc/Module/Install/DSL.pm line 14: the 1-argopenpath calledset()even on readonly literal scalars and read the filename from$_instead of the global scalar of the same name as the filehandle. Rewrote the 1-argopenblock inIOOperator.javato derive the filehandle name from a globref / bareword / numeric literal, look up$main::<name>for the filename (soopen 0reads from$0), register the IO on the named glob, and only write back toargs[0]when it is a writable scalar.2.
op/state.tregression (commit 0c40001)PR #589 (
fix(given/when): implicit break and skip smartmatch on boolean exprs) appended an implicitlast;to everywhenblock and marked the synthesizedgivenblock withBlockNode.isLoop = trueso the unlabeledlastexits the given block instead of escaping to the enclosing loop.The JVM backend (
EmitBlock.java) honorsisLoop. The interpreter backend (BytecodeCompiler.visit(BlockNode)) did not — it never pushed aLoopInfofor a bareBlockNodemarkedisLoop=true. So whenop/state.tfalls back to the interpreter ("Method too large, using interpreter backend"), the implicitlastfromwhenwalked past the given block onloopStack(where it wasn't even pushed) and broke out of the surroundingforeach, turning 4 iterations into 1 and droppingop/state.tfrom 159/170 to 156/170.Fix: in
BytecodeCompiler.visit(BlockNode), whennode.isLoopis true, push aLoopInfo(node.labelName, bodyStartPc, true)before compiling the statements (matches JVMEmitBlock'spushLoopLabels(... isBareBlock, isBareBlock)semantics — bare blocks are unlabeled-control-flow targets) and patch break/next/redo jumps after the body so block teardown (RESTORE_REGEX_STATE,POP_LOCAL_LEVEL,exitScope) still runs onlast/next.Test plan
make(full unit-test suite) passes.jcpan -t LWP::Online— PASS (8/8 tests).jcpan -t HTTP::Client::Parallel— PASS (live-internet test correctly skipped).op/state.trecovers from 156/170 → 159/170, with all 4 "given" subtests passing cleanly.Generated with Devin