Skip to content

Commit 6c94572

Browse files
committed
Speed up identity-cache hot path
intern_all hoists the cache lookup out of the loop and inlines what was a per-item method call to intern(). For accessors whose Rust bridge returns only nodes — get_child_nodes / get_descendant_nodes — a typed intern_nodes() variant skips the instanceof check entirely. The walk benchmark exercises the descendants accessors over ~4.8M nodes per run, so even small per-item savings add up.
1 parent 6bf1153 commit 6c94572

1 file changed

Lines changed: 53 additions & 3 deletions

File tree

packages/mysql-on-sqlite/src/mysql/native/class-wp-mysql-native-parser-node.php

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ public function get_child_nodes( ?string $rule_name = null ): array {
143143
if ( $this->was_mutated() ) {
144144
return parent::get_child_nodes( $rule_name );
145145
}
146-
return $this->intern_all( wp_sqlite_mysql_native_ast_get_child_nodes( $this->native_ast, $this->native_node_index, $rule_name ) );
146+
return $this->intern_nodes( wp_sqlite_mysql_native_ast_get_child_nodes( $this->native_ast, $this->native_node_index, $rule_name ) );
147147
}
148148

149149
/** @inheritDoc */
@@ -167,7 +167,7 @@ public function get_descendant_nodes( ?string $rule_name = null ): array {
167167
if ( $this->was_mutated() ) {
168168
return parent::get_descendant_nodes( $rule_name );
169169
}
170-
return $this->intern_all( wp_sqlite_mysql_native_ast_get_descendant_nodes( $this->native_ast, $this->native_node_index, $rule_name ) );
170+
return $this->intern_nodes( wp_sqlite_mysql_native_ast_get_descendant_nodes( $this->native_ast, $this->native_node_index, $rule_name ) );
171171
}
172172

173173
/** @inheritDoc */
@@ -231,12 +231,62 @@ private function intern( $value ) {
231231
/**
232232
* Intern every entry in an accessor return array.
233233
*
234+
* Hot path: this runs once per descendant when a caller walks the tree,
235+
* so cache lookup and the cache-miss write are inlined and the cache
236+
* reference is hoisted out of the loop.
237+
*
234238
* @param array $values
235239
* @return array
236240
*/
237241
private function intern_all( array $values ): array {
242+
if ( ! $values ) {
243+
return $values;
244+
}
245+
$cache = $this->cache ?? $this->ensure_cache();
246+
$nodes = &$cache->nodes;
247+
foreach ( $values as $i => $value ) {
248+
if ( ! $value instanceof WP_MySQL_Native_Parser_Node ) {
249+
continue;
250+
}
251+
$index = $value->native_node_index;
252+
if ( null === $index ) {
253+
continue;
254+
}
255+
if ( isset( $nodes[ $index ] ) ) {
256+
$values[ $i ] = $nodes[ $index ];
257+
} else {
258+
$value->cache = $cache;
259+
$nodes[ $index ] = $value;
260+
}
261+
}
262+
return $values;
263+
}
264+
265+
/**
266+
* Intern array of guaranteed-node results (no token/null mixing).
267+
*
268+
* Used by `get_child_nodes()` / `get_descendant_nodes()` whose Rust
269+
* bridge returns only WP_MySQL_Native_Parser_Node instances. Skips
270+
* the per-item `instanceof` check that intern_all() must do for the
271+
* mixed `get_children()` / `get_descendants()` arrays.
272+
*
273+
* @param array $values
274+
* @return array
275+
*/
276+
private function intern_nodes( array $values ): array {
277+
if ( ! $values ) {
278+
return $values;
279+
}
280+
$cache = $this->cache ?? $this->ensure_cache();
281+
$nodes = &$cache->nodes;
238282
foreach ( $values as $i => $value ) {
239-
$values[ $i ] = $this->intern( $value );
283+
$index = $value->native_node_index;
284+
if ( isset( $nodes[ $index ] ) ) {
285+
$values[ $i ] = $nodes[ $index ];
286+
} else {
287+
$value->cache = $cache;
288+
$nodes[ $index ] = $value;
289+
}
240290
}
241291
return $values;
242292
}

0 commit comments

Comments
 (0)