preload time monomorphization of functions#12
Open
henderkes wants to merge 30 commits into
Open
Conversation
Signed-off-by: azjezz <azjezz@protonmail.com>
Signed-off-by: Robert Landers <landers.robert@gmail.com>
Signed-off-by: Robert Landers <landers.robert@gmail.com>
Signed-off-by: Robert Landers <landers.robert@gmail.com>
Signed-off-by: Robert Landers <landers.robert@gmail.com>
Signed-off-by: Robert Landers <landers.robert@gmail.com>
Signed-off-by: Robert Landers <landers.robert@gmail.com>
Signed-off-by: Robert Landers <landers.robert@gmail.com> fix inheritance chaining Signed-off-by: Robert Landers <landers.robert@gmail.com> fix inheritance chaining Signed-off-by: Robert Landers <landers.robert@gmail.com>
Specialize concrete turbofish calls at compile time: Graph\dfs::<string,int>() compiles to a direct by-name call to the mangled monomorph and drops the per-call ZEND_VERIFY_GENERIC_ARGUMENTS opcode, making it byte-identical to a non-generic call. Monomorphs are synthesized and registered on first reference; the runtime verify/bind path remains as the fallback for non-concrete / inference-only call sites. Also: persist the generic value-check plan into opcache SHM, and gate destroy_op_array's monomorph-table scan on ZEND_ACC2_HAS_GENERIC_CALL_OPS so non-generic code is not taxed. PSL\Graph bench (aarch64, opcache, two-point Ir/iter): reified-vs-erased overhead 6.51%->4.14% (all) / 5.72%->4.19% (query); wall 9.04%->5.89% (no-JIT). Erased baseline unchanged; generics tax -37%. Digests identical across no-JIT/tracing/-n, generics .phpt 0 new regressions, valgrind-clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Robert Landers <landers.robert@gmail.com>
Turbofish monomorphs are shallow copies of their base op_array that share the opcode buffer (zend_synthesize_function_monomorph). The tracing JIT keys compiled code and patched opline handlers on opcode addresses and bakes op_array-specific constants (arg_info for RECV / VERIFY_RETURN_TYPE, inferred operand types, cached literals), which are valid for only one substituted arg_info layout. A trace compiled for one monomorph was therefore reused for a sibling carrying a different binding, enforcing the wrong type: e.g. nestedGen::<Fooable&Barable>($fb) was checked against an earlier nestedGen::<int|string> binding and wrongly threw "must be of type string|int" under opcache.jit=tracing (the interpreter and jit=disable were correct). The interpreter avoids this via the TRAIT_CLONE slow-path RECV; the JIT has no equivalent and the hazard is not limited to RECV, so keep monomorphizable generics and their monomorphs interpreted until per-monomorph JIT state exists. Signed-off-by: Robert Landers <landers.robert@gmail.com> Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
When a bare type-parameter leaf (`T $x`) is bound to a concrete generic instantiation via turbofish (e.g. `id::<DBox<L2<int>>>($v)`), the binding arrives as a pre-erasure named-with-args type. zend_substitute_leaf_type_param_origin returned it verbatim, so the synthesized monomorph's arg_info (and return type) kept the named-with-args payload. The reified RECV check then reached zend_fetch_ce_from_type(), which reads ZEND_TYPE_NAME() and interpreted that payload as a zend_string: at depth >= 2 it dereferenced a garbage length and tried a multi-terabyte allocation; at depth 1 it raised a spurious TypeError. Fold a fully concrete named-with-args binding to a plain CLASS reference to the monomorph's canonical class name, mirroring the named-with-args branch in the same function. That is the erased shape the runtime arg / property / return checks already understand, and it matches the class the value itself carries (so inference and turbofish now agree). Reproduces in the interpreter and under opcache; not JIT-specific. Signed-off-by: Robert Landers <landers.robert@gmail.com> Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
zend_try_synthesize_monomorph_by_name() backs the class-existence lookup path
(class_exists(), interface_exists(), is-a probes, the autoloader). It raised in
two cases: a non-generic base carrying type arguments ("Plain<int>") threw, and
an out-of-bound argument ("Box<int>" for Box<T : object>) reached
zend_synthesize_monomorph(), whose bound check fatals via zend_error_noreturn.
So class_exists('Box<int>') aborted with a fatal instead of returning false.
A name whose arguments are invalid simply names a class that does not exist, so
the lookup now reports "not found" (NULL): the non-generic case returns NULL
directly, and bounds are validated silently up front, returning NULL on
violation before synthesis. The throwing enforcement stays on the `new` /
type-declaration paths (compile-time and zend_synthesize_monomorph), where a
bound violation is a genuine error — verified that `new Box::<int>()` and a
`Plain<int>` type position still fatal.
Signed-off-by: Robert Landers <landers.robert@gmail.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Robert Landers <landers.robert@gmail.com>
…t happen to have the same name Signed-off-by: Robert Landers <landers.robert@gmail.com>
Signed-off-by: Robert Landers <landers.robert@gmail.com>
… also make monomorphs share static props Signed-off-by: Robert Landers <landers.robert@gmail.com>
Signed-off-by: Robert Landers <landers.robert@gmail.com>
Signed-off-by: Robert Landers <landers.robert@gmail.com>
Signed-off-by: Robert Landers <landers.robert@gmail.com>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
3335ce1 to
10d21f7
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.
No description provided.