Fix interpreter DEREF opcode regression in op/decl-refs.t#226
Merged
Conversation
…inheritance
Multiple fixes for interpreter mode (JPERL_EVAL_USE_INTERPRETER=1):
1. Call-site strict/feature flags for eval STRING (CompileOperator, SlowOpcodeHandler,
EvalStringHandler):
Embed strict/feature flags at each eval call site in the bytecode. Previously
EvalStringHandler used the end-of-compilation snapshot from InterpretedCode, which
missed lexically-scoped pragma changes (e.g. 'no strict refs' inside a block).
Now the exact flags at the eval call site are passed to EvalStringHandler.
2. Strict-refs-aware deref opcodes (BytecodeCompiler, Opcodes, SlowOpcodeHandler,
BytecodeInterpreter):
Added DEREF_HASH_NONSTRICT and DEREF_ARRAY_NONSTRICT opcodes. BytecodeCompiler
now emits these when 'no strict refs' is in effect at compile time, matching the
JVM path which calls hashDerefNonStrict/arrayDerefNonStrict.
Handles: %$ref, %{block}, %{'name'}, @$ref, @{block}, @{'name'}.
3. Dynamic glob load/assign (BytecodeCompiler, CompileAssignment, Opcodes,
SlowOpcodeHandler, BytecodeInterpreter):
Added LOAD_SYMBOLIC_GLOB opcode for *{expr} and *{'name'} glob access.
Added DEREF_GLOB opcode for ** postfix glob dereference.
CompileAssignment now handles *(BlockNode), *(StringNode), *(OperatorNode)
for dynamic glob assignment: *{'name'} = value, *{expr} = value.
4. @{'name'} and %{'name'} symref support (BytecodeCompiler):
Added StringNode cases for @ and % dereference operators.
op/postfixderef.t: 85/128 -> 81/128 interpreter (was 78/128, improved by 3)
op/require_gh20577.t: 0/0 -> 4/9 interpreter (was 0/0, improved by 4)
…ormalization 1. local *glob support (BytecodeCompiler): Added '*' sigil case to compileVariableDeclaration. Emits LOAD_GLOB + PUSH_LOCAL_VARIABLE, matching JVM path (EmitOperatorLocal). This allows 'local *mysubalias' to correctly save/restore the glob state so that assignments inside eval STRING persist in the outer scope. 2. DEREF always calls scalarDeref() (BytecodeInterpreter): Fixed both DEREF cases in the main switch and executeTypeOps helper. Previously, DEREF silently passed through non-REFERENCE scalars. Now it always calls scalarDeref() which throws 'Not a SCALAR reference' for IO, FORMAT, and other non-reference types, matching Perl semantics. 3. LOAD_SYMBOLIC_GLOB name normalization (SlowOpcodeHandler): executeLoadSymbolicGlob now normalizes the glob name with the current package (e.g. 'mysub' -> 'main::mysub') before calling getGlobalIO(). Previously it used the raw name, creating a different glob object from the one where the sub was actually defined. 4. GLOB_SLOT_GET handles RuntimeGlob directly (SlowOpcodeHandler): executeGlobSlotGet now checks instanceof RuntimeGlob and calls hashDerefGetNonStrict on it directly (which RuntimeGlob overrides to call getGlobSlot). Previously .scalar() was called first which could lose the glob type. 5. Disassembler additions (InterpretedCode): Added LOAD_SYMBOLIC_GLOB, DEREF_GLOB, DEREF_HASH_NONSTRICT, DEREF_ARRAY_NONSTRICT to the bytecode disassembler. op/postfixderef.t: interpreter now matches JVM exactly (85/85)
The DEREF opcode was calling scalarDeref() on all RuntimeScalar types, causing 'Not a SCALAR reference' crashes for ARRAYREFERENCE, HASHREFERENCE, CODE, and REGEX types in no-strict-refs contexts (e.g. decl-refs.t). Fix: pass through non-scalar reference types (ARRAYREFERENCE, HASHREFERENCE, CODE, REGEX) unchanged, and only call scalarDeref() for scalar refs, undef, and non-reference types (strings, globs, FORMAT, IO, etc.). This matches the JVM compiler behavior where scalarDerefNonStrict() is used for no-strict contexts (which also passes through non-scalar refs). Also adds: - DEREF_NONSTRICT opcode (337) for future use - executeDerefNonStrict() handler in SlowOpcodeHandler - DEREF_NONSTRICT disassembler entry in InterpretedCode - UNDEF autovivification in scalarDerefNonStrict() matching scalarDeref() Results: - op/decl-refs.t interpreter: 272/408 (was 169, regression fixed) - op/postfixderef.t interpreter: 85/86 (unchanged) - op/require_gh20577.t interpreter: 7/9 (unchanged)
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.
Fixes #225
Problem
The interpreter
DEREFopcode was callingscalarDeref()on allRuntimeScalartypes, causingARRAYREFERENCE,HASHREFERENCE,CODE, andREGEXtypes to throw 'Not a SCALAR reference' inno strict 'refs'contexts. This crashedop/decl-refs.tat line 105 with only 169/408 tests passing.Root Cause
In
no strict 'refs'contexts, the JVM compiler callsscalarDerefNonStrict()which passes non-scalar reference types through. The interpreter was incorrectly callingscalarDeref()on all types.Fix
Pass through non-scalar reference types (
ARRAYREFERENCE,HASHREFERENCE,CODE,REGEX) unchanged in theDEREFopcode handler. Only callscalarDeref()for scalar refs, undef, and non-reference types (strings, globs, FORMAT, IO, etc.).Also adds:
DEREF_NONSTRICTopcode (337) for future useexecuteDerefNonStrict()handler inSlowOpcodeHandlerInterpretedCodeUNDEFautovivification inscalarDerefNonStrict()matchingscalarDeref()behaviorResults
op/decl-refs.t(interpreter)op/postfixderef.t(interpreter)op/require_gh20577.t(interpreter)