Implement dead code elimination for constant conditionals#369
Open
Implement dead code elimination for constant conditionals#369
Conversation
This enables CPAN modules like IPC::System::Simple to work correctly
when they use patterns like:
use constant WINDOWS => 0;
if (WINDOWS) {
my $x = UNDEFINED_BAREWORD; # No longer causes compile error
}
Changes:
- constant.pm: Store constants directly in stash as references (like
native Perl) instead of creating subroutines. This ensures
RuntimeStashEntry sets constantValue on the RuntimeCode.
- EmitStatement.emitIf(): Add getConstantConditionValue() to detect
compile-time constant conditions and skip dead branches entirely.
- BytecodeCompiler.visit(IfNode): Same dead code elimination for the
bytecode interpreter backend.
- POSIX.pm: Export additional constants (O_RDWR, O_CREAT, WNOHANG,
WUNTRACED) needed by File::ShareDir.
Generated with [Devin](https://cli.devin.ai/docs)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
When Internals::SvREADONLY was called on a constant with a DOUBLE value, the value was being lost because the svReadonly method did not handle the DOUBLE type, causing it to fall through to the undef case. - Added handling for RuntimeScalarType.DOUBLE in Internals.svReadonly() - Added new RuntimeScalarReadOnly(double) constructor - Also handle BYTE_STRING type like STRING Fixes: use constant PI => 3.14; print PI; # now prints 3.14 Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
When SvREADONLY was called on a scalar containing an array or hash reference, it would fall through to the undef case and corrupt the reference. Now properly handles ARRAYREFERENCE, HASHREFERENCE, REFERENCE, CODE, and GLOBREFERENCE types by leaving them unchanged. Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…terals The RuntimeList copy constructor was sharing the elements list with the original instead of making a copy. When a constant subroutine returned its value via 'new RuntimeList(constantValue)', and that value was then consumed by addToArray() (which clears elements after adding them), the original constant's value was destroyed. This caused 'use constant FOO => -1' to return empty after 'use constant BAR => [FOO()]' was defined, because FOO()'s constantValue elements were cleared. Fix: Change RuntimeList(RuntimeList) constructor to create a shallow copy of the elements ArrayList instead of sharing it. Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
The systemCommand method for backticks was shifting the exit code
by 8 bits again even though executeCommand already returns the
wait status (which is already shifted via waitForProcessWithStatus).
This caused $? to have a value like 8323072 (127 << 16) instead of
32512 (127 << 8) when a shell command returned exit code 127.
This also includes improvements to system/exec for indirect object
syntax (e.g., system { $program } @Args).
Generated with [Devin](https://cli.devin.ai/docs)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
1. Backticks (qx) now bypass shell for simple commands without metacharacters, matching native Perl behavior. This allows proper detection of command not found errors (exit -1) instead of shell exit code 127. 2. Fix kill() to handle numeric string signals (e.g., 9 from @argv). Previously, string signals like 9 were incorrectly treated as named signals and failed lookup. 3. Fix Config.pm sig_name to include ZERO at index 0, matching Perl signal numbering where signal 0 is the null signal for process existence checks. These fixes allow IPC::System::Simple tests t/03_signal.t, t/04_capture.t, and t/06_fail.t to pass. Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
The isNonInterpolatingCharacter() method was incorrectly blocking interpolation of valid Perl special punctuation variables like $?, $|, $%, $", $\, and $#. These are all valid Perl special variables that should interpolate in double-quoted strings. The fix removes the incorrect character blocking - these special variables are already handled correctly by IdentifierParser.parseComplexIdentifier() which recognizes punctuation characters as valid variable names. Added test cases for special punctuation variable interpolation in string_interpolation.t to verify $?, $|, $%, $\, $(, and $) all interpolate correctly. Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
When a negative offset overshoots the string start:
- If adjusted length is negative: warn and return undef
Example: substr("hello", -10, 1) -> warn + undef
- If adjusted length is >= 0: clip to start, return substring (no warning)
Example: substr("a", -2, 1) -> "" (no warning)
Example: substr("a", -2, 2) -> "a" (no warning)
This fixes the substr warnings appearing in Test::More skip() calls.
Generated with [Devin](https://cli.devin.ai/docs)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
1. Fix -e flag to accept code immediately after the flag (e.g., -e1) - Matches Perl behavior where -e1 means -e "1" - Also fixes -E flag with the same pattern 2. Add WINDOWS and VMS constants to bundled IPC::System::Simple - Required for compatibility with CPAN test suite - Allows tests like t/internal.t to run correctly Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
1. RuntimeIO: Track 3-arg open form to bypass shell for single-element
command lists. This ensures capturex("cmd with args") properly fails
instead of invoking shell (matching Perl behavior for the x variants)
2. IPC::System::Simple: Add _spawn_or_die function and FAIL_INTERNAL
constant for Windows-only operations that throw Internal error on
non-Win32 platforms (required for t/internal.t)
3. Fix FAIL_INTERNAL capitalization to match expected Internal error
Test results: t/12_systemx.t now passes all 7 tests, t/internal.t passes
all 3 tests. Taint mode tests still fail/hang as expected since
PerlOnJava does not support taint mode.
Generated with [Devin](https://cli.devin.ai/docs)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
The separateMode tracking in RuntimeIO.openPipe was too aggressive - it treated ALL 3-arg pipe opens as no-shell mode, but open($fh, "-|", $cmd) with a single command string should still use shell interpretation. The proper fix for capturex shell bypass requires fork+exec which PerlOnJava doesn't support. Document this as a known limitation. This fixes regressions: - io/crlf_through.t: 0/942 -> 942/942 - io/through.t: 0/942 -> 942/942 - io/open.t: 165/216 -> 186/216 Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This enables capturex to properly bypass shell for single-arg commands.
Usage: open($fh, "-|:noshell", $cmd) treats $cmd as a literal program
name rather than a shell command. This emulates the behavior of native
Perl's fork+exec { $cmd } $cmd without requiring fork support.
IPC::System::Simple capturex now uses :noshell for single-arg calls,
making t/12_systemx.t pass all 7 tests while maintaining compatibility
with normal pipe open operations (io/open.t, io/through.t still pass).
Generated with [Devin](https://cli.devin.ai/docs)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
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
This PR implements dead code elimination for constant conditionals, enabling CPAN modules like
IPC::System::SimpleandFile::ShareDirto work correctly.Problem
CPAN modules often use patterns like:
Native Perl optimizes away the dead
ifbranch at compile time, so undefined barewords in dead code don't cause errors. PerlOnJava was compiling both branches, causing "Bareword not allowed" errors.Solution
constant.pm: Updated to store constants directly in the stash as references (
$stash->{$name} = \$value) like native Perl's constant.pm, instead of creating subroutines. This ensuresRuntimeStashEntrysetsconstantValueon theRuntimeCode.EmitStatement.emitIf(): Added
getConstantConditionValue()method to detect compile-time constant conditions (literal numbers, strings, or constant subroutine calls) and skip dead branches entirely.BytecodeCompiler.visit(IfNode): Same dead code elimination for the bytecode interpreter backend.
POSIX.pm: Export additional constants (O_RDWR, O_CREAT, WNOHANG, WUNTRACED) needed by File::ShareDir.
Internals::SvREADONLY: Fixed corruption of array/hash references when called with
SvREADONLY($arrayref, 1). Now properly handles ARRAYREFERENCE, HASHREFERENCE, REFERENCE, CODE, and GLOBREFERENCE types by leaving them unchanged.Test Results
if,unless,elsifuse constantuse constant ARR => [1,2,3]now works correctlyTest plan
makepassesGenerated with Devin