Skip to content

Commit 349b46e

Browse files
committed
v2/cleanc: cut memory blowup in generic scan loops + guard map/_or_t emits
scan_weak_specialization_body, discover_nested_generic_specs, and discover_direct_generic_call_specs already snapshot per-fn state via clone() and reset the fields to fresh empty maps for the work; the restore-side clone() then allocated a fresh copy of the snapshot just to discard it. Inside the 8x6x8 retry loop over all files * generic fns, those wasted clones were a major contributor to the gitly build memory blowup (down from 20-27 GB to ~3.75 GB peak RSS). Also: - emit_map_str_functions / emit_map_eq_functions: skip late-registered map aliases whose typedef wasn't emitted, otherwise the generated helper references an undeclared type. - expr.v: rewrite SelectorExpr on transformer-injected _or_t* temps so Option-typed temps use .state and Result-typed temps use .is_error, matching their actual C layout when the checker resolved the call to the wrong overload.
1 parent 0c40408 commit 349b46e

5 files changed

Lines changed: 58 additions & 34 deletions

File tree

vlib/v/checker/checker.v

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6410,12 +6410,12 @@ fn (mut c Checker) ident(mut node ast.Ident) ast.Type {
64106410
// Got a var with type T, return current generic type
64116411
if node.or_expr.kind != .absent {
64126412
if !info.typ.has_flag(.option) {
6413-
hint := c.smartcast_unwrap_hint(node.scope.find_var(node.name) or { unsafe { nil } })
6413+
hint :=
6414+
c.smartcast_unwrap_hint(node.scope.find_var(node.name) or { unsafe { nil } })
64146415
if node.or_expr.kind == .propagate_option {
64156416
c.error('cannot use `?` on non-option variable${hint}', node.pos)
64166417
} else if node.or_expr.kind == .block {
6417-
c.error('cannot use `or {}` block on non-option variable${hint}',
6418-
node.pos)
6418+
c.error('cannot use `or {}` block on non-option variable${hint}', node.pos)
64196419
}
64206420
}
64216421
unwrapped_typ := typ.clear_option_and_result()
@@ -6563,8 +6563,7 @@ fn (mut c Checker) ident(mut node ast.Ident) ast.Type {
65636563
if !typ.has_flag(.option) {
65646564
hint := c.smartcast_unwrap_hint(&obj)
65656565
if node.or_expr.kind == .propagate_option {
6566-
c.error('cannot use `?` on non-option variable${hint}',
6567-
node.pos)
6566+
c.error('cannot use `?` on non-option variable${hint}', node.pos)
65686567
} else if node.or_expr.kind == .block {
65696568
c.error('cannot use `or {}` block on non-option variable${hint}',
65706569
node.pos)

vlib/v2/gen/cleanc/cheaders.v

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -881,6 +881,12 @@ fn (mut g Gen) emit_map_str_functions() {
881881
if '${name}_str' in g.fn_return_types {
882882
continue
883883
}
884+
// Skip map aliases whose typedef wasn't emitted (late-registered aliases
885+
// that reference unresolved short-name types). Without a typedef, the
886+
// generated helper would reference an undeclared type.
887+
if 'alias_${name}' !in g.emitted_types {
888+
continue
889+
}
884890
// Parse key and value types from Map_K_V name
885891
without_prefix := name.all_after('Map_')
886892
key_type, value_type := g.parse_map_kv_types(without_prefix)
@@ -1053,6 +1059,10 @@ fn (mut g Gen) emit_map_eq_functions() {
10531059
mut map_names := g.map_aliases.keys()
10541060
map_names.sort()
10551061
for name in map_names {
1062+
// Skip late-registered map aliases without a typedef (see emit_map_str_functions).
1063+
if 'alias_${name}' !in g.emitted_types {
1064+
continue
1065+
}
10561066
without_prefix := name.all_after('Map_')
10571067
key_type, value_type := g.parse_map_kv_types(without_prefix)
10581068
if key_type == '' || value_type == '' {

vlib/v2/gen/cleanc/cleanc.v

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1686,7 +1686,7 @@ fn (mut g Gen) emit_weak_generic_specializations_from_non_emit_files() {
16861686
old_file := g.cur_file_name
16871687
old_module := g.cur_module
16881688
old_import_modules := g.cur_import_modules.clone()
1689-
old_active_generic_types := g.active_generic_types.clone()
1689+
old_active_generic_types := g.active_generic_types
16901690
mut needed_names := g.called_fn_names.clone()
16911691
mut scanned := map[string]bool{}
16921692
for _ in 0 .. 8 {
@@ -1715,10 +1715,10 @@ fn (mut g Gen) emit_weak_generic_specializations_from_non_emit_files() {
17151715
break
17161716
}
17171717
}
1718-
g.active_generic_types = old_active_generic_types.clone()
1718+
g.active_generic_types = old_active_generic_types
17191719
g.cur_file_name = old_file
17201720
g.cur_module = old_module
1721-
g.cur_import_modules = old_import_modules.clone()
1721+
g.cur_import_modules = old_import_modules
17221722
}
17231723

17241724
fn (mut g Gen) scan_weak_generic_specializations_from_non_emit_files(mut needed_names map[string]bool, mut scanned map[string]bool) {
@@ -1821,22 +1821,21 @@ fn (mut g Gen) scan_weak_specialization_body(node &ast.FnDecl, fn_name string, g
18211821
g.generic_scan_called_names = map[string]bool{}
18221822
g.seed_fn_scan_runtime_types(*node, fn_name)
18231823
g.scan_fn_body_for_generic_types(*node, fn_name)
1824-
scan_called_names := g.generic_scan_called_names.clone()
1824+
for name, _ in g.generic_scan_called_names {
1825+
needed_names[name] = true
1826+
}
18251827
g.cur_fn_name = prev_fn_name
18261828
g.cur_fn_c_name = prev_fn_c_name
18271829
g.cur_fn_scope = prev_fn_scope
1828-
g.active_generic_types = prev_active_generic_types.clone()
1829-
g.runtime_local_types = prev_runtime_local_types.clone()
1830-
g.runtime_decl_types = prev_runtime_decl_types.clone()
1831-
g.not_local_var_cache = prev_not_local_var_cache.clone()
1832-
g.is_module_ident_cache = prev_is_module_ident_cache.clone()
1833-
g.resolved_module_names = prev_resolved_module_names.clone()
1834-
g.cur_fn_generic_params = prev_cur_fn_generic_params.clone()
1830+
g.active_generic_types = prev_active_generic_types
1831+
g.runtime_local_types = prev_runtime_local_types
1832+
g.runtime_decl_types = prev_runtime_decl_types
1833+
g.not_local_var_cache = prev_not_local_var_cache
1834+
g.is_module_ident_cache = prev_is_module_ident_cache
1835+
g.resolved_module_names = prev_resolved_module_names
1836+
g.cur_fn_generic_params = prev_cur_fn_generic_params
18351837
g.collect_generic_scan_calls = prev_collect_generic_scan_calls
1836-
g.generic_scan_called_names = prev_generic_scan_called_names.clone()
1837-
for name, _ in scan_called_names {
1838-
needed_names[name] = true
1839-
}
1838+
g.generic_scan_called_names = prev_generic_scan_called_names
18401839
g.add_late_weak_generic_names_since(late_before, mut needed_names)
18411840
}
18421841

vlib/v2/gen/cleanc/expr.v

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2791,6 +2791,22 @@ fn (mut g Gen) expr(node ast.Expr) {
27912791
}
27922792
}
27932793
}
2794+
// Transformer-generated or-block temps (`_or_t*`) can end up with a
2795+
// field-name mismatch when the checker resolved the call to the wrong
2796+
// overload (e.g. `header.get` typed as `http.get`). Trust the temp's
2797+
// actual C type and rewrite the field name accordingly.
2798+
if lhs_expr is ast.Ident && lhs_expr.name.starts_with('_or_t') {
2799+
if rhs_name == 'is_error' && lhs_type.starts_with('_option_') {
2800+
g.sb.write_string(lhs_expr.name)
2801+
g.sb.write_string('.state')
2802+
return
2803+
}
2804+
if rhs_name == 'state' && lhs_type.starts_with('_result_') {
2805+
g.sb.write_string(lhs_expr.name)
2806+
g.sb.write_string('.is_error')
2807+
return
2808+
}
2809+
}
27942810
if variant_field := g.sum_data_variant_selector_field(sel) {
27952811
g.expr(lhs_expr)
27962812
g.sb.write_string('.${variant_field}')

vlib/v2/gen/cleanc/fn.v

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2190,13 +2190,13 @@ fn (mut g Gen) discover_nested_generic_specs() {
21902190
g.cur_fn_name = prev_fn_name
21912191
g.cur_fn_c_name = prev_fn_c_name
21922192
g.cur_fn_scope = prev_fn_scope
2193-
g.active_generic_types = prev_active_generic_types.clone()
2194-
g.runtime_local_types = prev_runtime_local_types.clone()
2195-
g.runtime_decl_types = prev_runtime_decl_types.clone()
2196-
g.not_local_var_cache = prev_not_local_var_cache.clone()
2197-
g.is_module_ident_cache = prev_is_module_ident_cache.clone()
2198-
g.resolved_module_names = prev_resolved_module_names.clone()
2199-
g.cur_fn_generic_params = prev_cur_fn_generic_params.clone()
2193+
g.active_generic_types = prev_active_generic_types
2194+
g.runtime_local_types = prev_runtime_local_types
2195+
g.runtime_decl_types = prev_runtime_decl_types
2196+
g.not_local_var_cache = prev_not_local_var_cache
2197+
g.is_module_ident_cache = prev_is_module_ident_cache
2198+
g.resolved_module_names = prev_resolved_module_names
2199+
g.cur_fn_generic_params = prev_cur_fn_generic_params
22002200
}
22012201
}
22022202
}
@@ -2262,13 +2262,13 @@ fn (mut g Gen) discover_direct_generic_call_specs() {
22622262
g.cur_fn_name = prev_fn_name
22632263
g.cur_fn_c_name = prev_fn_c_name
22642264
g.cur_fn_scope = prev_fn_scope
2265-
g.active_generic_types = prev_active_generic_types.clone()
2266-
g.runtime_local_types = prev_runtime_local_types.clone()
2267-
g.runtime_decl_types = prev_runtime_decl_types.clone()
2268-
g.not_local_var_cache = prev_not_local_var_cache.clone()
2269-
g.is_module_ident_cache = prev_is_module_ident_cache.clone()
2270-
g.resolved_module_names = prev_resolved_module_names.clone()
2271-
g.cur_fn_generic_params = prev_cur_fn_generic_params.clone()
2265+
g.active_generic_types = prev_active_generic_types
2266+
g.runtime_local_types = prev_runtime_local_types
2267+
g.runtime_decl_types = prev_runtime_decl_types
2268+
g.not_local_var_cache = prev_not_local_var_cache
2269+
g.is_module_ident_cache = prev_is_module_ident_cache
2270+
g.resolved_module_names = prev_resolved_module_names
2271+
g.cur_fn_generic_params = prev_cur_fn_generic_params
22722272
}
22732273
else {}
22742274
}

0 commit comments

Comments
 (0)