Skip to content

Commit b9a2d87

Browse files
authored
v3: promote scoped batch specialization names before freeing the arena (#28915)
1 parent fe01b59 commit b9a2d87

2 files changed

Lines changed: 57 additions & 5 deletions

File tree

‎vlib/v/transform/scoped_merge_notd_v3_no_parallel_test.v‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,36 @@ fn test_scoped_monomorph_specialization_args_are_deep_cloned() {
5454
assert owned_args == ['cloud.Body', '[]string']
5555
}
5656

57+
fn test_scoped_batch_specialization_names_outlive_scratch_scope() {
58+
mut a := flat.FlatAst.new()
59+
mut tc := types.TypeChecker.new(&a)
60+
mut t := new_transformer(mut a, &tc, map[string]bool{})
61+
t.a.specialized_fn_modules[3] = 'builtin'
62+
t.a.specialized_fn_files[3] = 'builtin.v'
63+
nodes_len := t.a.specialized_fn_nodes.len
64+
modules_len := t.a.specialized_fn_modules.len
65+
files_len := t.a.specialized_fn_files.len
66+
67+
// A scoped batch records the module/file names of the functions it
68+
// specializes, and those names can live in the batch's scratch arena
69+
// (vlang/v#28897).
70+
scope := transform_worker_scope_begin(true)
71+
t.a.specialized_fn_nodes[7] = true
72+
t.a.specialized_fn_modules[7] = 'main'.clone()
73+
t.a.specialized_fn_files[7] = 'main.v'.clone()
74+
transform_worker_scope_leave(scope)
75+
76+
t.promote_scoped_specialization_maps(scope, nodes_len, modules_len, files_len)
77+
assert !transform_scope_owns(scope, t.a.specialized_fn_modules[7].str)
78+
assert !transform_scope_owns(scope, t.a.specialized_fn_files[7].str)
79+
transform_worker_scope_free(scope)
80+
assert t.a.specialized_fn_nodes[7]
81+
assert t.a.specialized_fn_modules[7] == 'main'
82+
assert t.a.specialized_fn_files[7] == 'main.v'
83+
assert t.a.specialized_fn_modules[3] == 'builtin'
84+
assert t.a.specialized_fn_files[3] == 'builtin.v'
85+
}
86+
5787
fn test_generic_unresolved_cache_owns_scoped_module() {
5888
mut a := flat.FlatAst.new()
5989
mut tc := types.TypeChecker.new(&a)

‎vlib/v/transform/transform_parallel_notd_v3_no_parallel.v‎

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
20482068
fn (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

Comments
 (0)