Repository navigation
symfony/demo compiles and serves every page identically to php - #599
Merged
Merged
Conversation
… a union, not an integer add
…heir registers do not dominate the join
…y default can name a global constant
…ne name chain re-emitted the receiver per candidate (3M IR lines in one Doctrine method)
…d), narrowing skips them, $cls::cases()/from()/tryFrom() resolve enum classes
… table, so a class declared in a guarded if gets reflection, var_dump, serialize arms (Fixes #566)
…Handler defaults name them
… #[AsCommand(help: self::HELP)] resolves
… the string or object arm by tag
…y name, not by a variadic first declarer that trims them (lost Definition::addTag's attributes)
…lee returned a borrowed argument (Fixes #569)
…nt of its own, so $v = $f($v) no longer frees the result (Fixes #569)
…in (same display name), which sent a name-keyed lookup in circles
…ser TokenPolyfill) takes the eager path, so the return ends the file, not the program
…n the class-isa table (autoconfigure by ServiceSubscriberInterface matched nothing)
…picks the string/object arm by tag
…eResource saw them as missing)
…e*/newInstanceArgs build ArrayObject, DateTime, Spl*
…lves (Symfony service factory 'array_first')
…r, call the static symbol (the receiver shifted every argument; corrupted Request::getPreferredLanguage)
…][] = x) lands in the stored value (Twig ExpressionParsers::getPrecedenceChanges crashed)
…riadic under their names (LogRecord::with(message:, context:) lost the keys)
…ature (names were dropped when 'with' was ambiguous by name)
…path (the element was released but left in the array: Twig Node::removeNode)
…ect's first property became the bag pointer: Twig's getAttribute) and stringifies a non-string name
…le turned every iterator into [] and the blog rendered empty; array union reads an entry kind only on a hashed source
…rite throws; Twig read private properties directly and never called the getter
… gone by the first resume
…ys did, so a Twig template's loop over an ArrayIterator rendered its empty branch
…al to its own cell: an array callable was released once per listener and freed under its owner, crashing the second request
…ect's runtime class: UrlGenerator's caster walked private properties across the object graph and crashed the login redirect
…te or test of an unset slot, for the classes a manifest's lazy lists or every user class
…rest of the program compiles as before
…ordinary markup, over the DOM classes; html-sanitizer's parser needs it
…in the request attributes made the login redirect throw
…ROVIDE_OBJECT, php's default); defines the DEBUG_BACKTRACE_* constants
…parser now records
…file they were written in, trace records carry it per frame, and built-in frames leave file/line out as php does
…obal referenced from another global was missing from the split part that held the record
…a: the next arena allocation overwrote it and Doctrine's date hydration crashed in __mc_dt_slot_store
…d the HTTP server presents itself as the front controller /index.php: Symfony's cache retries on "File exists", and its base URL came from the CLI's ./bin/app
…, a setup script that fetches the rest at a pinned commit, and the requirements and steps to build and run it; document the manifest's lazy key
…er: the filler returns its own, and every call leaked one
…he hidden slot owns, and leave a pre-evaluated value to its owner (WeakMap $m[$k][$j] = fresh leaked per write)
blacktrs
force-pushed
the
examples/symfony-demo
branch
from
November 8, 2026 13:47
4bcb526 to
7cc3942
Compare
…er enum cases answered a cell for an ordinal and crashed (array_endpoint_objects)
…1.3.2 (Alpine) counts the dictionary header in total_in at Z_NEED_DICT, 1.2.x does not
blacktrs
added a commit
that referenced
this pull request
Nov 9, 2026
…, cycle collection through untyped properties, #599 regressions (#602) * Cut clang memory and IR volume of large builds: no MachineOutliner (a Laravel part 13.7 GB -> 4.65 GB), one cold raise per guard site, table dispatch for $o->$name on a known class, nounwind runtime helpers called not invoked, cell_int_bad slow path out of line * Release per-request leaks found in Laravel: a minting builtin's discarded result, and a cell or array union read as borrowed in a conditional arm or a local * Seed the init map of a fresh instance with its untyped properties: in a program that makes lazy ghosts every untyped read before a write was the uninitialized-property Error (Laravel Application::$appPath at boot) * A closure generator owns its env in the frame (env@56), so an invoke releases the +1 a conditional or literal callee holds: Laravel's call_user_func($cb ?? $default, ...) leaked the closure and all it captured per request * Walk an object in an untyped (cell) property as a cycle-collector child and release a collected node's other cell slots: no cycle through an untyped property was ever collected, which kept Laravel's per-request Request/Route/closure graph and every string it held * Promote the 8 known-bug repros that pass now (4 already had identical cases; spread_into_variadic_closure lands as _repro beside a different case of that name) Fixes #541 Fixes #375 Fixes #517 Fixes #463 Fixes #476 Fixes #477 Fixes #565 Fixes #464 * is_a() with a runtime string subject releases a minted subject after the compares: the strval() an erased subject is unboxed by leaked one class name per Laravel container make() * Release three more per-request Laravel leaks: an owned call result used as a callee (call_user_func($this->getRouteResolver())), a closure stored raw in a reference box whose cell drop skipped it ($default in Router::substituteImplicitBindings), and (array) over a minting operand retained again (Router::resolveMiddleware) * Release a callable-typed call result invoked as a callee by its runtime representation: call_user_func($this->getRouteResolver()) with @return \Closure leaked Laravel's route resolver and its Route per request * Keep one representation for an inherited property: once any class of the slot holds a bare cell, every class of it does. Model::$attributes celled through the parent while Note kept vec[cell], so Note's drop released a tagged word as an array buffer and every Laravel /api/notes request crashed
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.
Goal
Run the full symfony/demo application — Symfony 8.1, Doctrine ORM 3.6, Twig, Symfony UX, security, 30 locales — as one native binary, rendering what php renders.
Result
From a single long-lived process, every page with a php reference is byte-identical to php 8.5 (render timestamps and the port aside):
//en/blog/,/en/blog/page/2,/uk/blog//en/blog/posts/{slug}/en/blog/rss.xml/en/login/en/admin/post//en/blog/searchexamples/symfony-demo/holds only the overlay (entry, kernel, manifest, warm-up scripts, compat shims) and asetup.shthat fetches upstream at a pinned commit. Its README explains the requirements, the build-time php steps and why they exist, the run-time environment, and what differs from upstream.What changed in the compiler and runtime
New capabilities
ReflectionClass::newLazyGhost,initializeLazyObject,markLazyObjectAsInitialized,isUninitializedLazyObject,setRawValueWithoutLazyInitialization. The initializer runs on the first read, write,issetor??of an unset slot. Candidate classes are listed by the new manifest keylazy(documented indocs/modules.md); only those pay for the check.Dom\HTMLDocument::createFromString— a tokenizer and tree builder for ordinary markup (html-sanitizer).debug_backtraceprovides each method frame'sobject(DEBUG_BACKTRACE_*constants added).Throwable::getTrace/getFile) names its own call site's file in a multi-file build; frames called from built-in code leave file/line out, as php does.ReflectionMethod::getEndLine(the parser records the closing line).http_build_querywalks objects by their public properties;fopenreports its failure to the installed error handler.Correctness and memory fixes (each with a test or a promoted repro)
callablereturned from a cell property was released without a count (crashed the second request); a callable compared unequal to its own cell.foreachover an erased base walked arrays only.$o->$name,get_object_varsandis_iterable/is_countablenow follow php's visibility and Traversable/Countable rules./index.php(Symfony derived its base URL from./bin/app).Fixes #566, fixes #569, fixes #576, fixes #587. New issues filed along the way: #588, #589, #593, #594.
Verification done
-ksubsets for every area touched (generators, foreach, callables, closures, dispatch, reflection, lazy, traces, fibers, exceptions, io, http, dom, static, arena).tests/aot/xfail.sh: no XPASS left (the one that appeared was promoted).setup.shrun from scratch on an overlay-only copy reproduces the warmed caches.Still owed before merge
tools/docker/run_tests.sh --gate): the changes touch ownership, generators, dispatch and the backtrace runtime.closure-typed local is never released.