Interpreter improvements: Close test gap with compiler to 0 tests#215
Merged
Conversation
When interpreter executes code from eval STRING (sourceName starts with "(eval N)"), exceptions are now passed through without wrapping them in formatInterpreterError(). This preserves clean error messages in $@ that match the compiler's behavior. Impact on re/regexp.t with JPERL_EVAL_USE_INTERPRETER=1: - Before: 1738/2210 passing (78.6%) - After: 1785/2210 passing (80.8%) - Improvement: +47 tests (+2.1 percentage points) This closes the gap between interpreter and compiler to just 1 test (1786 compiler vs 1785 interpreter). Example error message improvement: Before: Interpreter error in (eval 6) line 1 (pc=7): Invalid [] range... After: Invalid [] range "b-a" in regex; marked by <-- HERE... Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fixed two issues with scalar reference dereference in the interpreter:
1. DEREF opcode was just copying the reference instead of dereferencing it.
Now properly calls scalarDeref() on the reference to get the target value.
2. LOAD_SYMBOLIC_SCALAR was treating all block results as variable names for
symbolic references (like ${"varname"}). Now checks if the block returns a
REFERENCE type and dereferences it (like ${\(0)}), otherwise treats it as
a symbolic variable name.
This fixes the inline scalar reference dereference syntax ${\...} which is used
in Perl for patterns like:
- ${\(0)} - create anonymous scalar ref and dereference it
- ${\(defined($1)?1:0)} - conditional expression in scalar ref
Impact on re/regexp.t with JPERL_EVAL_USE_INTERPRETER=1:
- Before: 1785/2210 passing (80.8%)
- After: 1786/2210 passing (80.8%)
- Gap closed: Interpreter now matches compiler exactly (0 test difference)
Test case that now works:
eval q{my $x = ${\(0)}; say $x} # Now prints "0" instead of ""
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The DEREF opcode was unconditionally casting to RuntimeScalar, which caused
ClassCastException when processing declared reference lists like `my (\$f, $g)`.
Now checks the value type before attempting dereference:
- If RuntimeScalar with REFERENCE type: calls scalarDeref()
- If RuntimeScalar without REFERENCE type: passes through unchanged
- If RuntimeList or other type: passes through unchanged
This maintains the fix for ${\(0)} while handling list contexts correctly.
Impact on perl5_t/t/op/decl-refs.t with JPERL_EVAL_USE_INTERPRETER=1:
- Before regression: 270/408 passing (66.2%)
- After regression: 157/408 passing (38.5%) - ClassCastException crash
- After this fix: 272/408 passing (66.7%) - actually 2 tests better!
Impact on perl5_t/t/re/regexp.t with JPERL_EVAL_USE_INTERPRETER=1:
- Still passing: 1786/2210 (80.8%) - no regression
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.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 contains a series of improvements to the bytecode interpreter that closes the test gap between interpreter and compiler execution modes. The interpreter now achieves parity with the compiler on
re/regexp.t, with both passing 1786/2210 tests (80.8%).Key Achievements
✅ Interpreter vs Compiler Gap: 0 tests (was 48+ tests)
✅ perf/benchmarks.t: 100% pass rate with interpreter (1960/1960)
✅ re/regexp.t: 80.8% pass rate (1786/2210) - matches compiler exactly
✅ op/decl-refs.t: 66.7% pass rate (272/408) - 2 tests better than compiler (270/408)
✅ BytecodeInterpreter size: 8,228 bytes (under 8KB JIT limit)
Changes
1. BytecodeInterpreter Optimization (#1136003)
OpcodeHandlerExtendedandOpcodeHandlerFileTestexecute()method size from 12,066 bytes to 8,228 bytes2. Interpreter Feature Additions
SPRINTFopcode supportCHOPopcode support=~binding to perform actual match3. Register Management Fixes
4. Error Message Improvements (#ad5807d)
$@that match compiler behaviorre/regexp.t(1738 → 1785 passing)5. Scalar Reference Dereference (#ebc92fa + #7f14e66)
DEREFopcode behavior for scalar referencesLOAD_SYMBOLIC_SCALARto handle reference dereferencing${\...}syntax in interpreter (e.g.,${\(0)})re/regexp.t: 1785 → 1786 passingmy (\$f, $g)op/decl-refs.twent from 157/408 (crash) → 272/408 (66.7%)Testing
make test)re/regexp.t: 1786/2210 (80.8%) with both compiler and interpreterop/decl-refs.t: 272/408 (66.7%) with interpreter vs 270/408 (66.2%) with compilerperf/benchmarks.t: 1960/1960 (100%) with interpreterImpact
re/regexp.t - Before This PR
re/regexp.t - After This PR
op/decl-refs.t - After Regression Fix
The interpreter now provides identical or better functionality compared to the compiler while staying under the JVM JIT compilation threshold for optimal performance.
🤖 Generated with Claude Code