fix(overload): honor no overloading for arithmetic ops; load XSLoader early#520
Merged
fix(overload): honor no overloading for arithmetic ops; load XSLoader early#520
no overloading for arithmetic ops; load XSLoader early#520Conversation
…er early
Three related fixes uncovered while investigating `./jcpan -t Hash::Ordered`:
1. `no overloading` was only honored for string concatenation and `join`.
Arithmetic ops (`+`, `-`, `*`, `/`, `%`, `**`, unary `-`) still dispatched
through the overload machinery, so `sub _numify { no overloading; 0+$_[0] }`
recursed into its own `0+` overload and blew the JVM stack. This caused
Hash::Ordered's t/basic.t to die with `Deep recursion on subroutine
"Hash::Ordered::_numify"` / `StackOverflowError`.
Fix: mirror the existing `stringConcatNoOverload` / `joinNoOverload` pattern
for arithmetic.
- `RuntimeScalar.getNumberNoOverload()` — returns refaddr-style integer for
blessed refs, bypassing `Overload.numify`.
- `MathOperators.{add,subtract,multiply,divide,modulus,pow,unaryMinus}NoOverload`.
- `OperatorHandler.getNoOverload(op)` + registered `_noOverload` variants for
`+ - * / % ** unaryMinus`.
- `EmitOperator.emitOperator` prefers the NoOverload variant when
`HINT_NO_AMAGIC` is set in the current lexical scope (same mechanism
already used for concat/join).
2. Bytecode-interpreter parity for the above. The interpreter had no
equivalent of the JVM-backend's NoOverload dispatch for arithmetic.
- New opcodes `ADD_NO_OVERLOAD`..`POW_NO_OVERLOAD`, `NEG_NO_OVERLOAD`.
- `CompileBinaryOperatorHelper` and `CompileOperator` emit them when
`isNoOverloadingEnabled()` is true.
- `InlineOpcodeHandler` implements the runtime handlers; `BytecodeInterpreter`
dispatches them; `Disassemble` prints them.
3. `XSLoader::load` was undefined at startup on the interpreter backend,
which made *every* interpreter invocation die with
`Undefined subroutine &XSLoader::load called at jar:PERL5LIB/strict.pm line 12`.
Root cause: in `GlobalContext.initializeGlobals()`, `DynaLoader.initialize()`
triggered `require(Exporter.pm)` → `use strict;` → `require(strict.pm)`,
whose top-level calls `XSLoader::load(...)`. On the interpreter backend that
top-level actually runs (the JVM backend caches the code ref differently and
masks the issue). But `XSLoader.initialize()` was scheduled *after* DynaLoader,
so the global codeRef was only a symbolic-reference stub with no method
handle — `defined()` returned true while `apply()` threw
`Undefined subroutine &XSLoader::load`.
Fix: move `XSLoader.initialize()` ahead of `DynaLoader.initialize()` (and
before `Builtin.initialize()`), with a comment explaining the ordering
requirement.
Verification:
- `./jcpan -t Hash::Ordered` — before: 1/4 test programs failed with
`StackOverflowError`; after: all 112 tests pass.
- `./jperl --interpreter -e '...'` — now runs (previously died on startup).
- `./jperl --interpreter /tmp/test_no_overloading.pl` — exercises the new
`NEG_NO_OVERLOAD` / arithmetic NoOverload opcodes in the interpreter.
- `make` — full unit test suite passes.
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
Three related fixes surfaced while investigating
./jcpan -t Hash::Ordered:1. Honor
no overloadingfor arithmetic operatorsHash::Ordereddefines its numification overload as:PerlOnJava honored
HINT_NO_AMAGIC(the compile-time flag set byno overloading) only for string concatenation andjoin. Arithmetic ops (+,-,*,/,%,**, unary-) still went through the overload dispatch machinery, so0+$_[0]recursed into the0+overload and blew the JVM stack. Hash::Ordered'st/basic.tdied withDeep recursion on subroutine "Hash::Ordered::_numify"/StackOverflowError.Mirrors the existing
stringConcatNoOverload/joinNoOverloadpattern:RuntimeScalar.getNumberNoOverload()— bypassesOverload.numify, returning refaddr-style integer for blessed refs.MathOperators.{add,subtract,multiply,divide,modulus,pow,unaryMinus}NoOverload.OperatorHandler.getNoOverload(op)+ registered_noOverloadvariants.EmitOperator.emitOperatorprefers the NoOverload variant whenHINT_NO_AMAGICis set in scope.2. Bytecode-interpreter parity
Added NoOverload opcodes so the interpreter backend honors
no overloadingfor arithmetic too:ADD_NO_OVERLOAD..POW_NO_OVERLOAD,NEG_NO_OVERLOAD.CompileBinaryOperatorHelper/CompileOperatoremit them whenisNoOverloadingEnabled().InlineOpcodeHandler/BytecodeInterpreterdispatch;Disassembleprints.3.
XSLoader::loadundefined at startup on the interpreter backendEvery
./jperl --interpreter ...invocation died with:Root cause: in
GlobalContext.initializeGlobals(),DynaLoader.initialize()triggeredrequire(Exporter.pm)→use strict;→require(strict.pm), whose top-level callsXSLoader::load(...). On the interpreter backend that top-level actually runs (the JVM backend caches code refs differently and masks the issue), butXSLoader.initialize()was scheduled after DynaLoader — so the global codeRef was only a symbolic-reference stub with no method handle.defined()returned true whileapply()threw "Undefined subroutine".Fix: move
XSLoader.initialize()ahead ofDynaLoader.initialize()(and beforeBuiltin.initialize()), with a comment explaining why.Test plan
./jcpan -t Hash::Ordered— before: 1/4 test programs failed (StackOverflowError); after: all 112 tests pass../jperl --interpreter -e '...'— now runs; previously died on startup../jperl --interpreter /tmp/test_no_overloading.pl— exercises the newNEG_NO_OVERLOAD/ arithmetic NoOverload opcodes on the interpreter.make— full unit test suite passes.Generated with Devin