@@ -2031,18 +2031,38 @@ fn (mut t Transformer) promote_scoped_ast_storage(scope voidptr) {
20312031// the active one, so the map's storage grows inside an arena that is released at
20322032// the end of the batch - while the entries themselves are read much later, by
20332033// merge_worker, out of the helper the master is merging.
2034- fn (mut t Transformer) promote_scoped_specialization_maps (nodes_len int , modules_len int , files_len int ) {
2034+ fn (mut t Transformer) promote_scoped_specialization_maps (scope voidptr , nodes_len int , modules_len int , files_len int ) {
20352035 if t.a.specialized_fn_nodes.len != nodes_len {
20362036 t.a.specialized_fn_nodes = t.a.specialized_fn_nodes.clone ()
20372037 }
20382038 if t.a.specialized_fn_modules.len != modules_len {
2039- t.a.specialized_fn_modules = t.a.specialized_fn_modules.clone ()
2039+ t.a.specialized_fn_modules = promote_scoped_specialization_texts (t.a.specialized_fn_modules,
2040+ scope)
20402041 }
20412042 if t.a.specialized_fn_files.len != files_len {
2042- t.a.specialized_fn_files = t.a.specialized_fn_files.clone ()
2043+ t.a.specialized_fn_files = promote_scoped_specialization_texts (t.a.specialized_fn_files,
2044+ scope)
20432045 }
20442046}
20452047
2048+ // promote_scoped_specialization_texts clones a specialization table and every
2049+ // module/file name in it that still lives in `scope`. `map.clone()` copies the
2050+ // string values bitwise, and a batch can record names from its own
2051+ // declaration-context table, which is rebuilt inside the scratch arena
2052+ // (vlang/v#28897).
2053+ fn promote_scoped_specialization_texts (values map [int ]string , scope voidptr ) map [int ]string {
2054+ mut promoted := values.clone ()
2055+ if scope == unsafe { nil } {
2056+ return promoted
2057+ }
2058+ for idx, value in values {
2059+ if value.len > 0 && transform_scope_owns (scope, value.str) {
2060+ promoted[idx] = value.clone ()
2061+ }
2062+ }
2063+ return promoted
2064+ }
2065+
20462066// absorb_scoped_batch publishes one batch's observable state into the helper's
20472067// result arena before its large scratch arena is released.
20482068fn (mut t Transformer) absorb_scoped_batch (batch & Transformer, scope voidptr , new_node_start int ) {
@@ -2217,7 +2237,8 @@ fn (mut t Transformer) transform_scoped_helper_batches(items []FnWorkItem, max_b
22172237 t.absorb_scoped_batch (batch, scratch_scope, new_node_start)
22182238 storage_state := transform_stage_scope_suspend (t.merge_scratch_scope)
22192239 t.promote_scoped_ast_storage (scratch_scope)
2220- t.promote_scoped_specialization_maps (spec_nodes_len, spec_modules_len, spec_files_len)
2240+ t.promote_scoped_specialization_maps (scratch_scope, spec_nodes_len, spec_modules_len,
2241+ spec_files_len)
22212242 transform_stage_scope_resume (t.merge_scratch_scope, storage_state)
22222243 for item in items[start..end] {
22232244 if item.fn_idx > = 0 && item.fn_idx < t.transformed_fns.len {
@@ -2298,7 +2319,8 @@ fn (mut t Transformer) transform_late_candidates_scoped(candidate_index map[stri
22982319 t.a.promote_transform_texts_from (text_start, scratch_scope)
22992320 t.absorb_scoped_batch (batch, scratch_scope, new_node_start)
23002321 t.promote_scoped_ast_storage (scratch_scope)
2301- t.promote_scoped_specialization_maps (spec_nodes_len, spec_modules_len, spec_files_len)
2322+ t.promote_scoped_specialization_maps (scratch_scope, spec_nodes_len, spec_modules_len,
2323+ spec_files_len)
23022324 transform_worker_scope_free (scratch_scope)
23032325 for si, ci in selected {
23042326 idx := candidates[ci].idx
0 commit comments