Commit b47b748
authored
Move native AST identity cache into the Rust extension (#392)
Stacked on #391.
#391 restored `WP_Parser_Node` identity semantics by interning native
child wrappers in PHP. That fixed correctness, but the PHP-side cache
formed a retention cycle and added measurable cost to hit-heavy
translator-style workloads.
This PR moves native wrapper identity out of PHP object properties
entirely:
- `WP_MySQL_Native_Parser_Node` no longer stores `$native_ast`,
`$native_node_index`, or a PHP-side identity-cache object.
- Native bridge calls now pass the wrapper itself, e.g.
`wp_sqlite_mysql_native_ast_get_children( $this )`.
- The Rust extension keeps a thread-local registry keyed by the PHP
wrapper object pointer.
- Registry entries map wrapper pointer -> `(NativeAstState, node_index,
is_materialized)`, and each AST keeps a node-index -> wrapper-pointer
cache.
- Cached wrapper hits return the existing PHP object by pointer with its
refcount bumped; the cache does not own a PHP reference.
- `__destruct()` releases a wrapper from the Rust registry.
Materialization marks the wrapper as detached from native reads while
leaving it discoverable from the parent cache as long as it is still
live.
That breaks the cycle that mattered here: PHP wrappers no longer
strongly reference a native AST object, and Rust no longer strongly
references PHP wrappers. PHP's cycle collector can collect wrapper
graphs normally; destructors then clean up the Rust registry entries.
Tokens remain un-interned. The public token API has no mutators, and no
caller in this repo relies on token object identity.
## Perf numbers
From the passing `Native AST Walk Perf` CI run on this head
(`2d93be25f599c3c4482480a6ab644d61b9337b12`), comparing this PR to the
native no-cache baseline (`codex/native-lazy-ast-facade`):
| Scenario | This PR | Baseline | Duration delta | Peak memory delta |
|---|---:|---:|---:|---:|
| parse only | 1.2859s, 54,098 qps, 30.0MB | 1.2715s, 54,711 qps, 30.0MB
| +1.1% | 0.0% |
| walk x1 | 3.3265s, 20,912 qps, 48.0MB | 3.4191s, 20,346 qps, 60.5MB |
-2.7% | -20.7% |
| rewalk x10 | 8.6352s, 8,056 qps, 52.0MB | 16.9658s, 4,100 qps, 90.5MB
| -49.1% | -42.5% |
| reread x20 | 1.8618s, 37,364 qps, 30.0MB | 2.4322s, 28,602 qps, 38.0MB
| -23.5% | -21.1% |
| subtree x5 | 9.8274s, 7,078 qps, 48.0MB | 13.8921s, 5,007 qps, 64.5MB
| -29.3% | -25.6% |
The parse-only path is effectively unchanged. The repeated-access
workloads this cache is meant to help are materially faster and use less
peak memory.
For context, the same CI run measured the pure-PHP path at:
| Scenario | Pure PHP |
|---|---:|
| parse only | 13.5292s, 5,142 qps, 68.0MB |
| walk x1 | 16.1332s, 4,312 qps, 70.0MB |
## Safety coverage
The PR now includes native-extension tests for:
- stable wrapper identity across repeated child/descendant reads;
- no reflected `$native_ast` / `$native_node_index` properties on
wrappers;
- child mutations surviving repeat reads and parent materialization;
- materialized children remaining discoverable from a still-native
parent;
- repeated parse/walk/drop loops staying memory-bounded;
- dropping root and descendant wrappers reclaiming registry entries;
- child wrappers outliving root variables without use-after-free;
- overlapping AST lifetimes not corrupting each other;
- mutation-before-drop and rewalk loops staying memory-bounded.
CI smoke checks also assert the SQLite-driver and WordPress
test-container paths select the native wrapper model and do not regress
back to `$native_ast` storage.
## Test plan
- [x] `cargo check` for `packages/php-ext-wp-mysql-parser`
- [x] `cargo fmt --check` for `packages/php-ext-wp-mysql-parser`
- [x] PHP lint on changed PHP files
- [x] Focused native identity/cycle PHPUnit tests with the Rust
extension loaded
- [x] Full `packages/mysql-on-sqlite` PHPUnit suite with the Rust
extension loaded
- [x] Full GitHub Actions suite on PR head
- [x] Native AST Walk Perf workflow on PR head1 parent 2c07dac commit b47b748
9 files changed
Lines changed: 667 additions & 448 deletions
File tree
- .github/workflows
- packages
- mysql-on-sqlite
- src
- mysql/native
- tests/mysql/native
- php-ext-wp-mysql-parser/src
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
144 | 144 | | |
145 | 145 | | |
146 | 146 | | |
147 | | - | |
148 | | - | |
149 | | - | |
150 | | - | |
| 147 | + | |
151 | 148 | | |
152 | 149 | | |
153 | 150 | | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
154 | 172 | | |
155 | 173 | | |
156 | 174 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
38 | 38 | | |
39 | 39 | | |
40 | 40 | | |
41 | | - | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
42 | 58 | | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
43 | 66 | | |
44 | 67 | | |
45 | 68 | | |
| |||
Lines changed: 26 additions & 4 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
125 | 125 | | |
126 | 126 | | |
127 | 127 | | |
128 | | - | |
129 | | - | |
130 | | - | |
131 | 128 | | |
132 | | - | |
| 129 | + | |
133 | 130 | | |
134 | 131 | | |
135 | 132 | | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
136 | 158 | | |
137 | 159 | | |
138 | 160 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
27 | 27 | | |
28 | 28 | | |
29 | 29 | | |
30 | | - | |
31 | 30 | | |
32 | 31 | | |
33 | 32 | | |
| |||
Lines changed: 0 additions & 23 deletions
This file was deleted.
0 commit comments