@@ -37,17 +37,6 @@ extern "C" {
3737 value : * mut zval ,
3838 ) ;
3939
40- /// PHP's per-thread GC scratch buffer for `get_gc` handlers. The
41- /// handler reports the object's outgoing references by adding zvals
42- /// here, then `zend_get_gc_buffer_use` writes the buffer's contents
43- /// into the (table, n) out-params the cycle collector reads.
44- fn zend_get_gc_buffer_create ( ) -> * mut std:: ffi:: c_void ;
45- fn zend_get_gc_buffer_add_zval ( buffer : * mut std:: ffi:: c_void , zv : * mut zval ) ;
46- fn zend_get_gc_buffer_use (
47- buffer : * mut std:: ffi:: c_void ,
48- table : * mut * mut zval ,
49- n : * mut std:: os:: raw:: c_int ,
50- ) ;
5140}
5241
5342/// `Z_TYPE_INFO` for an OBJECT zval that carries a refcount.
@@ -1079,6 +1068,13 @@ pub struct WpMySqlNativeAst {
10791068 /// bumped, skipping the allocation and four `zend_update_property`
10801069 /// calls of the construction path.
10811070 node_cache : RefCell < HashMap < usize , ZBox < ZendObject > > > ,
1071+ /// Scratch buffer the custom `get_gc` handler refills on each
1072+ /// invocation with zvals pointing at every cached wrapper. We can't
1073+ /// use PHP's `zend_get_gc_buffer_*` API because PHP 8.2 builds on
1074+ /// Ubuntu's `shivammathur/setup-php` don't export those symbols, so
1075+ /// we own the buffer ourselves and hand its raw pointer to PHP via
1076+ /// the `(table, n)` out-params of the gc handler.
1077+ gc_trace : RefCell < Vec < zval > > ,
10821078}
10831079
10841080impl NativeAstArena {
@@ -1274,27 +1270,37 @@ unsafe extern "C" fn ast_get_gc(
12741270 table : * mut * mut zval ,
12751271 n : * mut std:: os:: raw:: c_int ,
12761272) -> * mut HashTable {
1277- let buf = zend_get_gc_buffer_create ( ) ;
1278-
1279- if let Some ( ast) =
1280- ext_php_rs:: types:: ZendClassObject :: < WpMySqlNativeAst > :: from_zend_obj ( & * object)
1281- . and_then ( |z| z. obj . as_ref ( ) )
1282- {
1283- if let Ok ( cache) = ast. node_cache . try_borrow ( ) {
1284- for boxed in cache. values ( ) {
1285- // Build a zval pointing at the cached wrapper without
1286- // bumping refcount — the gc buffer just enumerates outgoing
1287- // references; mutating refcounts here would un-balance the
1288- // collector's accounting.
1289- let mut zv: zval = std:: mem:: zeroed ( ) ;
1290- zv. value . obj = ( boxed. as_ref ( ) as * const ZendObject ) as * mut zend_object as * mut _ ;
1291- zv. u1 . type_info = PHP_IS_OBJECT_EX ;
1292- zend_get_gc_buffer_add_zval ( buf, & mut zv) ;
1293- }
1294- }
1295- }
1273+ * table = std:: ptr:: null_mut ( ) ;
1274+ * n = 0 ;
1275+
1276+ let Some ( ast) = ext_php_rs:: types:: ZendClassObject :: < WpMySqlNativeAst > :: from_zend_obj ( & * object)
1277+ . and_then ( |z| z. obj . as_ref ( ) )
1278+ else {
1279+ return std:: ptr:: null_mut ( ) ;
1280+ } ;
1281+
1282+ let Ok ( cache) = ast. node_cache . try_borrow ( ) else {
1283+ return std:: ptr:: null_mut ( ) ;
1284+ } ;
1285+ let Ok ( mut trace) = ast. gc_trace . try_borrow_mut ( ) else {
1286+ return std:: ptr:: null_mut ( ) ;
1287+ } ;
12961288
1297- zend_get_gc_buffer_use ( buf, table, n) ;
1289+ trace. clear ( ) ;
1290+ trace. reserve ( cache. len ( ) ) ;
1291+ for boxed in cache. values ( ) {
1292+ // Build a zval pointing at the cached wrapper without bumping
1293+ // refcount — the GC scan just enumerates outgoing references;
1294+ // mutating refcounts here would un-balance the collector's
1295+ // accounting.
1296+ let mut zv: zval = std:: mem:: zeroed ( ) ;
1297+ zv. value . obj = ( boxed. as_ref ( ) as * const ZendObject ) as * mut zend_object as * mut _ ;
1298+ zv. u1 . type_info = PHP_IS_OBJECT_EX ;
1299+ trace. push ( zv) ;
1300+ }
1301+
1302+ * table = trace. as_mut_ptr ( ) ;
1303+ * n = trace. len ( ) as std:: os:: raw:: c_int ;
12981304 std:: ptr:: null_mut ( )
12991305}
13001306
@@ -1932,6 +1938,7 @@ impl WpMySqlNativeParser {
19321938 let native_ast_zval = WpMySqlNativeAst {
19331939 arena,
19341940 node_cache : RefCell :: new ( HashMap :: new ( ) ) ,
1941+ gc_trace : RefCell :: new ( Vec :: new ( ) ) ,
19351942 }
19361943 . into_zval ( false )
19371944 . map_err ( php_error) ?;
0 commit comments